refactor!: amazon mws integration (#29438)
* remove: amazon mws integration
* add patch to remove doctype
* remove old patch
diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/__init__.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/__init__.py
+++ /dev/null
diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py
deleted file mode 100644
index 29bc36f..0000000
--- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py
+++ /dev/null
@@ -1,524 +0,0 @@
-# Copyright (c) 2018, Frappe Technologies and contributors
-# For license information, please see license.txt
-
-
-import csv
-import math
-import time
-from io import StringIO
-
-import dateutil
-import frappe
-from frappe import _
-
-import erpnext.erpnext_integrations.doctype.amazon_mws_settings.amazon_mws_api as mws
-
-
-#Get and Create Products
-def get_products_details():
- products = get_products_instance()
- reports = get_reports_instance()
-
- mws_settings = frappe.get_doc("Amazon MWS Settings")
- market_place_list = return_as_list(mws_settings.market_place_id)
-
- for marketplace in market_place_list:
- report_id = request_and_fetch_report_id("_GET_FLAT_FILE_OPEN_LISTINGS_DATA_", None, None, market_place_list)
-
- if report_id:
- listings_response = reports.get_report(report_id=report_id)
-
- #Get ASIN Codes
- string_io = StringIO(frappe.safe_decode(listings_response.original))
- csv_rows = list(csv.reader(string_io, delimiter='\t'))
- asin_list = list(set([row[1] for row in csv_rows[1:]]))
- #break into chunks of 10
- asin_chunked_list = list(chunks(asin_list, 10))
-
- #Map ASIN Codes to SKUs
- sku_asin = [{"asin":row[1],"sku":row[0]} for row in csv_rows[1:]]
-
- #Fetch Products List from ASIN
- for asin_list in asin_chunked_list:
- products_response = call_mws_method(products.get_matching_product,marketplaceid=marketplace,
- asins=asin_list)
-
- matching_products_list = products_response.parsed
- for product in matching_products_list:
- skus = [row["sku"] for row in sku_asin if row["asin"]==product.ASIN]
- for sku in skus:
- create_item_code(product, sku)
-
-def get_products_instance():
- mws_settings = frappe.get_doc("Amazon MWS Settings")
- products = mws.Products(
- account_id = mws_settings.seller_id,
- access_key = mws_settings.aws_access_key_id,
- secret_key = mws_settings.secret_key,
- region = mws_settings.region,
- domain = mws_settings.domain
- )
-
- return products
-
-def get_reports_instance():
- mws_settings = frappe.get_doc("Amazon MWS Settings")
- reports = mws.Reports(
- account_id = mws_settings.seller_id,
- access_key = mws_settings.aws_access_key_id,
- secret_key = mws_settings.secret_key,
- region = mws_settings.region,
- domain = mws_settings.domain
- )
-
- return reports
-
-#returns list as expected by amazon API
-def return_as_list(input_value):
- if isinstance(input_value, list):
- return input_value
- else:
- return [input_value]
-
-#function to chunk product data
-def chunks(l, n):
- for i in range(0, len(l), n):
- yield l[i:i+n]
-
-def request_and_fetch_report_id(report_type, start_date=None, end_date=None, marketplaceids=None):
- reports = get_reports_instance()
- report_response = reports.request_report(report_type=report_type,
- start_date=start_date,
- end_date=end_date,
- marketplaceids=marketplaceids)
-
- report_request_id = report_response.parsed["ReportRequestInfo"]["ReportRequestId"]["value"]
- generated_report_id = None
- #poll to get generated report
- for x in range(1,10):
- report_request_list_response = reports.get_report_request_list(requestids=[report_request_id])
- report_status = report_request_list_response.parsed["ReportRequestInfo"]["ReportProcessingStatus"]["value"]
-
- if report_status == "_SUBMITTED_" or report_status == "_IN_PROGRESS_":
- #add time delay to wait for amazon to generate report
- time.sleep(15)
- continue
- elif report_status == "_CANCELLED_":
- break
- elif report_status == "_DONE_NO_DATA_":
- break
- elif report_status == "_DONE_":
- generated_report_id = report_request_list_response.parsed["ReportRequestInfo"]["GeneratedReportId"]["value"]
- break
- return generated_report_id
-
-def call_mws_method(mws_method, *args, **kwargs):
-
- mws_settings = frappe.get_doc("Amazon MWS Settings")
- max_retries = mws_settings.max_retry_limit
-
- for x in range(0, max_retries):
- try:
- response = mws_method(*args, **kwargs)
- return response
- except Exception as e:
- delay = math.pow(4, x) * 125
- frappe.log_error(message=e, title=f'Method "{mws_method.__name__}" failed')
- time.sleep(delay)
- continue
-
- mws_settings.enable_sync = 0
- mws_settings.save()
-
- frappe.throw(_("Sync has been temporarily disabled because maximum retries have been exceeded"))
-
-def create_item_code(amazon_item_json, sku):
- if frappe.db.get_value("Item", sku):
- return
-
- item = frappe.new_doc("Item")
-
- new_manufacturer = create_manufacturer(amazon_item_json)
- new_brand = create_brand(amazon_item_json)
-
- mws_settings = frappe.get_doc("Amazon MWS Settings")
-
- item.item_code = sku
- item.amazon_item_code = amazon_item_json.ASIN
- item.item_group = mws_settings.item_group
- item.description = amazon_item_json.Product.AttributeSets.ItemAttributes.Title
- item.brand = new_brand
- item.manufacturer = new_manufacturer
-
- item.image = amazon_item_json.Product.AttributeSets.ItemAttributes.SmallImage.URL
-
- temp_item_group = amazon_item_json.Product.AttributeSets.ItemAttributes.ProductGroup
-
- item_group = frappe.db.get_value("Item Group",filters={"item_group_name": temp_item_group})
-
- if not item_group:
- igroup = frappe.new_doc("Item Group")
- igroup.item_group_name = temp_item_group
- igroup.parent_item_group = mws_settings.item_group
- igroup.insert()
-
- item.append("item_defaults", {'company':mws_settings.company})
-
- item.insert(ignore_permissions=True)
- create_item_price(amazon_item_json, item.item_code)
-
- return item.name
-
-def create_manufacturer(amazon_item_json):
- if not amazon_item_json.Product.AttributeSets.ItemAttributes.Manufacturer:
- return None
-
- existing_manufacturer = frappe.db.get_value("Manufacturer",
- filters={"short_name":amazon_item_json.Product.AttributeSets.ItemAttributes.Manufacturer})
-
- if not existing_manufacturer:
- manufacturer = frappe.new_doc("Manufacturer")
- manufacturer.short_name = amazon_item_json.Product.AttributeSets.ItemAttributes.Manufacturer
- manufacturer.insert()
- return manufacturer.short_name
- else:
- return existing_manufacturer
-
-def create_brand(amazon_item_json):
- if not amazon_item_json.Product.AttributeSets.ItemAttributes.Brand:
- return None
-
- existing_brand = frappe.db.get_value("Brand",
- filters={"brand":amazon_item_json.Product.AttributeSets.ItemAttributes.Brand})
- if not existing_brand:
- brand = frappe.new_doc("Brand")
- brand.brand = amazon_item_json.Product.AttributeSets.ItemAttributes.Brand
- brand.insert()
- return brand.brand
- else:
- return existing_brand
-
-def create_item_price(amazon_item_json, item_code):
- item_price = frappe.new_doc("Item Price")
- item_price.price_list = frappe.db.get_value("Amazon MWS Settings", "Amazon MWS Settings", "price_list")
- if not("ListPrice" in amazon_item_json.Product.AttributeSets.ItemAttributes):
- item_price.price_list_rate = 0
- else:
- item_price.price_list_rate = amazon_item_json.Product.AttributeSets.ItemAttributes.ListPrice.Amount
-
- item_price.item_code = item_code
- item_price.insert()
-
-#Get and create Orders
-def get_orders(after_date):
- try:
- orders = get_orders_instance()
- statuses = ["PartiallyShipped", "Unshipped", "Shipped", "Canceled"]
- mws_settings = frappe.get_doc("Amazon MWS Settings")
- market_place_list = return_as_list(mws_settings.market_place_id)
-
- orders_response = call_mws_method(orders.list_orders, marketplaceids=market_place_list,
- fulfillment_channels=["MFN", "AFN"],
- lastupdatedafter=after_date,
- orderstatus=statuses,
- max_results='50')
-
- while True:
- orders_list = []
-
- if "Order" in orders_response.parsed.Orders:
- orders_list = return_as_list(orders_response.parsed.Orders.Order)
-
- if len(orders_list) == 0:
- break
-
- for order in orders_list:
- create_sales_order(order, after_date)
-
- if not "NextToken" in orders_response.parsed:
- break
-
- next_token = orders_response.parsed.NextToken
- orders_response = call_mws_method(orders.list_orders_by_next_token, next_token)
-
- except Exception as e:
- frappe.log_error(title="get_orders", message=e)
-
-def get_orders_instance():
- mws_settings = frappe.get_doc("Amazon MWS Settings")
- orders = mws.Orders(
- account_id = mws_settings.seller_id,
- access_key = mws_settings.aws_access_key_id,
- secret_key = mws_settings.secret_key,
- region= mws_settings.region,
- domain= mws_settings.domain,
- version="2013-09-01"
- )
-
- return orders
-
-def create_sales_order(order_json,after_date):
- customer_name = create_customer(order_json)
- create_address(order_json, customer_name)
-
- market_place_order_id = order_json.AmazonOrderId
-
- so = frappe.db.get_value("Sales Order",
- filters={"amazon_order_id": market_place_order_id},
- fieldname="name")
-
- taxes_and_charges = frappe.db.get_value("Amazon MWS Settings", "Amazon MWS Settings", "taxes_charges")
-
- if so:
- return
-
- if not so:
- items = get_order_items(market_place_order_id)
- delivery_date = dateutil.parser.parse(order_json.LatestShipDate).strftime("%Y-%m-%d")
- transaction_date = dateutil.parser.parse(order_json.PurchaseDate).strftime("%Y-%m-%d")
-
- so = frappe.get_doc({
- "doctype": "Sales Order",
- "naming_series": "SO-",
- "amazon_order_id": market_place_order_id,
- "marketplace_id": order_json.MarketplaceId,
- "customer": customer_name,
- "delivery_date": delivery_date,
- "transaction_date": transaction_date,
- "items": items,
- "company": frappe.db.get_value("Amazon MWS Settings", "Amazon MWS Settings", "company")
- })
-
- try:
- if taxes_and_charges:
- charges_and_fees = get_charges_and_fees(market_place_order_id)
- for charge in charges_and_fees.get("charges"):
- so.append('taxes', charge)
-
- for fee in charges_and_fees.get("fees"):
- so.append('taxes', fee)
-
- so.insert(ignore_permissions=True)
- so.submit()
-
- except Exception as e:
- import traceback
- frappe.log_error(message=traceback.format_exc(), title="Create Sales Order")
-
-def create_customer(order_json):
- order_customer_name = ""
-
- if not("BuyerName" in order_json):
- order_customer_name = "Buyer - " + order_json.AmazonOrderId
- else:
- order_customer_name = order_json.BuyerName
-
- existing_customer_name = frappe.db.get_value("Customer",
- filters={"name": order_customer_name}, fieldname="name")
-
- if existing_customer_name:
- filters = [
- ["Dynamic Link", "link_doctype", "=", "Customer"],
- ["Dynamic Link", "link_name", "=", existing_customer_name],
- ["Dynamic Link", "parenttype", "=", "Contact"]
- ]
-
- existing_contacts = frappe.get_list("Contact", filters)
-
- if existing_contacts:
- pass
- else:
- new_contact = frappe.new_doc("Contact")
- new_contact.first_name = order_customer_name
- new_contact.append('links', {
- "link_doctype": "Customer",
- "link_name": existing_customer_name
- })
- new_contact.insert()
-
- return existing_customer_name
- else:
- mws_customer_settings = frappe.get_doc("Amazon MWS Settings")
- new_customer = frappe.new_doc("Customer")
- new_customer.customer_name = order_customer_name
- new_customer.customer_group = mws_customer_settings.customer_group
- new_customer.territory = mws_customer_settings.territory
- new_customer.customer_type = mws_customer_settings.customer_type
- new_customer.save()
-
- new_contact = frappe.new_doc("Contact")
- new_contact.first_name = order_customer_name
- new_contact.append('links', {
- "link_doctype": "Customer",
- "link_name": new_customer.name
- })
-
- new_contact.insert()
-
- return new_customer.name
-
-def create_address(amazon_order_item_json, customer_name):
-
- filters = [
- ["Dynamic Link", "link_doctype", "=", "Customer"],
- ["Dynamic Link", "link_name", "=", customer_name],
- ["Dynamic Link", "parenttype", "=", "Address"]
- ]
-
- existing_address = frappe.get_list("Address", filters)
-
- if not("ShippingAddress" in amazon_order_item_json):
- return None
- else:
- make_address = frappe.new_doc("Address")
-
- if "AddressLine1" in amazon_order_item_json.ShippingAddress:
- make_address.address_line1 = amazon_order_item_json.ShippingAddress.AddressLine1
- else:
- make_address.address_line1 = "Not Provided"
-
- if "City" in amazon_order_item_json.ShippingAddress:
- make_address.city = amazon_order_item_json.ShippingAddress.City
- else:
- make_address.city = "Not Provided"
-
- if "StateOrRegion" in amazon_order_item_json.ShippingAddress:
- make_address.state = amazon_order_item_json.ShippingAddress.StateOrRegion
-
- if "PostalCode" in amazon_order_item_json.ShippingAddress:
- make_address.pincode = amazon_order_item_json.ShippingAddress.PostalCode
-
- for address in existing_address:
- address_doc = frappe.get_doc("Address", address["name"])
- if (address_doc.address_line1 == make_address.address_line1 and
- address_doc.pincode == make_address.pincode):
- return address
-
- make_address.append("links", {
- "link_doctype": "Customer",
- "link_name": customer_name
- })
- make_address.address_type = "Shipping"
- make_address.insert()
-
-def get_order_items(market_place_order_id):
- mws_orders = get_orders_instance()
-
- order_items_response = call_mws_method(mws_orders.list_order_items, amazon_order_id=market_place_order_id)
- final_order_items = []
-
- order_items_list = return_as_list(order_items_response.parsed.OrderItems.OrderItem)
-
- warehouse = frappe.db.get_value("Amazon MWS Settings", "Amazon MWS Settings", "warehouse")
-
- while True:
- for order_item in order_items_list:
-
- if not "ItemPrice" in order_item:
- price = 0
- else:
- price = order_item.ItemPrice.Amount
-
- final_order_items.append({
- "item_code": get_item_code(order_item),
- "item_name": order_item.SellerSKU,
- "description": order_item.Title,
- "rate": price,
- "qty": order_item.QuantityOrdered,
- "stock_uom": "Nos",
- "warehouse": warehouse,
- "conversion_factor": "1.0"
- })
-
- if not "NextToken" in order_items_response.parsed:
- break
-
- next_token = order_items_response.parsed.NextToken
-
- order_items_response = call_mws_method(mws_orders.list_order_items_by_next_token, next_token)
- order_items_list = return_as_list(order_items_response.parsed.OrderItems.OrderItem)
-
- return final_order_items
-
-def get_item_code(order_item):
- sku = order_item.SellerSKU
- item_code = frappe.db.get_value("Item", {"item_code": sku}, "item_code")
- if item_code:
- return item_code
-
-def get_charges_and_fees(market_place_order_id):
- finances = get_finances_instance()
-
- charges_fees = {"charges":[], "fees":[]}
-
- response = call_mws_method(finances.list_financial_events, amazon_order_id=market_place_order_id)
-
- shipment_event_list = return_as_list(response.parsed.FinancialEvents.ShipmentEventList)
-
- for shipment_event in shipment_event_list:
- if shipment_event:
- shipment_item_list = return_as_list(shipment_event.ShipmentEvent.ShipmentItemList.ShipmentItem)
-
- for shipment_item in shipment_item_list:
- charges, fees = [], []
-
- if 'ItemChargeList' in shipment_item.keys():
- charges = return_as_list(shipment_item.ItemChargeList.ChargeComponent)
-
- if 'ItemFeeList' in shipment_item.keys():
- fees = return_as_list(shipment_item.ItemFeeList.FeeComponent)
-
- for charge in charges:
- if(charge.ChargeType != "Principal") and float(charge.ChargeAmount.CurrencyAmount) != 0:
- charge_account = get_account(charge.ChargeType)
- charges_fees.get("charges").append({
- "charge_type":"Actual",
- "account_head": charge_account,
- "tax_amount": charge.ChargeAmount.CurrencyAmount,
- "description": charge.ChargeType + " for " + shipment_item.SellerSKU
- })
-
- for fee in fees:
- if float(fee.FeeAmount.CurrencyAmount) != 0:
- fee_account = get_account(fee.FeeType)
- charges_fees.get("fees").append({
- "charge_type":"Actual",
- "account_head": fee_account,
- "tax_amount": fee.FeeAmount.CurrencyAmount,
- "description": fee.FeeType + " for " + shipment_item.SellerSKU
- })
-
- return charges_fees
-
-def get_finances_instance():
-
- mws_settings = frappe.get_doc("Amazon MWS Settings")
-
- finances = mws.Finances(
- account_id = mws_settings.seller_id,
- access_key = mws_settings.aws_access_key_id,
- secret_key = mws_settings.secret_key,
- region= mws_settings.region,
- domain= mws_settings.domain,
- version="2015-05-01"
- )
-
- return finances
-
-def get_account(name):
- existing_account = frappe.db.get_value("Account", {"account_name": "Amazon {0}".format(name)})
- account_name = existing_account
- mws_settings = frappe.get_doc("Amazon MWS Settings")
-
- if not existing_account:
- try:
- new_account = frappe.new_doc("Account")
- new_account.account_name = "Amazon {0}".format(name)
- new_account.company = mws_settings.company
- new_account.parent_account = mws_settings.market_place_account_group
- new_account.insert(ignore_permissions=True)
- account_name = new_account.name
- except Exception as e:
- frappe.log_error(message=e, title="Create Account")
-
- return account_name
diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_api.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_api.py
deleted file mode 100755
index 4caf137..0000000
--- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_api.py
+++ /dev/null
@@ -1,651 +0,0 @@
-#!/usr/bin/env python
-#
-# Basic interface to Amazon MWS
-# Based on http://code.google.com/p/amazon-mws-python
-# Extended to include finances object
-
-import base64
-import hashlib
-import hmac
-import re
-from urllib.parse import quote
-
-from erpnext.erpnext_integrations.doctype.amazon_mws_settings import xml_utils
-
-try:
- from xml.etree.ElementTree import ParseError as XMLError
-except ImportError:
- from xml.parsers.expat import ExpatError as XMLError
-
-from time import gmtime, strftime
-
-from requests import request
-from requests.exceptions import HTTPError
-
-__all__ = [
- 'Feeds',
- 'Inventory',
- 'MWSError',
- 'Reports',
- 'Orders',
- 'Products',
- 'Recommendations',
- 'Sellers',
- 'Finances'
-]
-
-# See https://images-na.ssl-images-amazon.com/images/G/01/mwsportal/doc/en_US/bde/MWSDeveloperGuide._V357736853_.pdf page 8
-# for a list of the end points and marketplace IDs
-
-MARKETPLACES = {
- "CA": "https://mws.amazonservices.ca", #A2EUQ1WTGCTBG2
- "US": "https://mws.amazonservices.com", #ATVPDKIKX0DER",
- "DE": "https://mws-eu.amazonservices.com", #A1PA6795UKMFR9
- "ES": "https://mws-eu.amazonservices.com", #A1RKKUPIHCS9HS
- "FR": "https://mws-eu.amazonservices.com", #A13V1IB3VIYZZH
- "IN": "https://mws.amazonservices.in", #A21TJRUUN4KGV
- "IT": "https://mws-eu.amazonservices.com", #APJ6JRA9NG5V4
- "UK": "https://mws-eu.amazonservices.com", #A1F83G8C2ARO7P
- "JP": "https://mws.amazonservices.jp", #A1VC38T7YXB528
- "CN": "https://mws.amazonservices.com.cn", #AAHKV2X7AFYLW
- "AE": " https://mws.amazonservices.ae", #A2VIGQ35RCS4UG
- "MX": "https://mws.amazonservices.com.mx", #A1AM78C64UM0Y8
- "BR": "https://mws.amazonservices.com", #A2Q3Y263D00KWC
-}
-
-
-class MWSError(Exception):
- """
- Main MWS Exception class
- """
- # Allows quick access to the response object.
- # Do not rely on this attribute, always check if its not None.
- response = None
-
-def calc_md5(string):
- """Calculates the MD5 encryption for the given string
- """
- md = hashlib.md5()
- md.update(string)
- return base64.encodebytes(md.digest()).decode().strip()
-
-
-
-def remove_empty(d):
- """
- Helper function that removes all keys from a dictionary (d),
- that have an empty value.
- """
- for key in list(d):
- if not d[key]:
- del d[key]
- return d
-
-def remove_namespace(xml):
- xml = xml.decode('utf-8')
- regex = re.compile(' xmlns(:ns2)?="[^"]+"|(ns2:)|(xml:)')
- return regex.sub('', xml)
-
-class DictWrapper(object):
- def __init__(self, xml, rootkey=None):
- self.original = xml
- self._rootkey = rootkey
- self._mydict = xml_utils.xml2dict().fromstring(remove_namespace(xml))
- self._response_dict = self._mydict.get(list(self._mydict)[0], self._mydict)
-
- @property
- def parsed(self):
- if self._rootkey:
- return self._response_dict.get(self._rootkey)
- else:
- return self._response_dict
-
-class DataWrapper(object):
- """
- Text wrapper in charge of validating the hash sent by Amazon.
- """
- def __init__(self, data, header):
- self.original = data
- if 'content-md5' in header:
- hash_ = calc_md5(self.original)
- if header['content-md5'] != hash_:
- raise MWSError("Wrong Contentlength, maybe amazon error...")
-
- @property
- def parsed(self):
- return self.original
-
-class MWS(object):
- """ Base Amazon API class """
-
- # This is used to post/get to the different uris used by amazon per api
- # ie. /Orders/2011-01-01
- # All subclasses must define their own URI only if needed
- URI = "/"
-
- # The API version varies in most amazon APIs
- VERSION = "2009-01-01"
-
- # There seem to be some xml namespace issues. therefore every api subclass
- # is recommended to define its namespace, so that it can be referenced
- # like so AmazonAPISubclass.NS.
- # For more information see http://stackoverflow.com/a/8719461/389453
- NS = ''
-
- # Some APIs are available only to either a "Merchant" or "Seller"
- # the type of account needs to be sent in every call to the amazon MWS.
- # This constant defines the exact name of the parameter Amazon expects
- # for the specific API being used.
- # All subclasses need to define this if they require another account type
- # like "Merchant" in which case you define it like so.
- # ACCOUNT_TYPE = "Merchant"
- # Which is the name of the parameter for that specific account type.
- ACCOUNT_TYPE = "SellerId"
-
- def __init__(self, access_key, secret_key, account_id, region='US', domain='', uri="", version=""):
- self.access_key = access_key
- self.secret_key = secret_key
- self.account_id = account_id
- self.version = version or self.VERSION
- self.uri = uri or self.URI
-
- if domain:
- self.domain = domain
- elif region in MARKETPLACES:
- self.domain = MARKETPLACES[region]
- else:
- error_msg = "Incorrect region supplied ('%(region)s'). Must be one of the following: %(marketplaces)s" % {
- "marketplaces" : ', '.join(MARKETPLACES.keys()),
- "region" : region,
- }
- raise MWSError(error_msg)
-
- def make_request(self, extra_data, method="GET", **kwargs):
- """Make request to Amazon MWS API with these parameters
- """
-
- # Remove all keys with an empty value because
- # Amazon's MWS does not allow such a thing.
- extra_data = remove_empty(extra_data)
-
- params = {
- 'AWSAccessKeyId': self.access_key,
- self.ACCOUNT_TYPE: self.account_id,
- 'SignatureVersion': '2',
- 'Timestamp': self.get_timestamp(),
- 'Version': self.version,
- 'SignatureMethod': 'HmacSHA256',
- }
- params.update(extra_data)
- request_description = '&'.join(['%s=%s' % (k, quote(params[k], safe='-_.~')) for k in sorted(params)])
- signature = self.calc_signature(method, request_description)
- url = '%s%s?%s&Signature=%s' % (self.domain, self.uri, request_description, quote(signature))
- headers = {'User-Agent': 'python-amazon-mws/0.0.1 (Language=Python)'}
- headers.update(kwargs.get('extra_headers', {}))
-
- try:
- # Some might wonder as to why i don't pass the params dict as the params argument to request.
- # My answer is, here i have to get the url parsed string of params in order to sign it, so
- # if i pass the params dict as params to request, request will repeat that step because it will need
- # to convert the dict to a url parsed string, so why do it twice if i can just pass the full url :).
- response = request(method, url, data=kwargs.get('body', ''), headers=headers)
- response.raise_for_status()
- # When retrieving data from the response object,
- # be aware that response.content returns the content in bytes while response.text calls
- # response.content and converts it to unicode.
- data = response.content
-
- # I do not check the headers to decide which content structure to server simply because sometimes
- # Amazon's MWS API returns XML error responses with "text/plain" as the Content-Type.
- try:
- parsed_response = DictWrapper(data, extra_data.get("Action") + "Result")
- except XMLError:
- parsed_response = DataWrapper(data, response.headers)
-
- except HTTPError as e:
- error = MWSError(str(e))
- error.response = e.response
- raise error
-
- # Store the response object in the parsed_response for quick access
- parsed_response.response = response
- return parsed_response
-
- def get_service_status(self):
- """
- Returns a GREEN, GREEN_I, YELLOW or RED status.
- Depending on the status/availability of the API its being called from.
- """
-
- return self.make_request(extra_data=dict(Action='GetServiceStatus'))
-
- def calc_signature(self, method, request_description):
- """Calculate MWS signature to interface with Amazon
- """
- sig_data = method + '\n' + self.domain.replace('https://', '').lower() + '\n' + self.uri + '\n' + request_description
- sig_data = sig_data.encode('utf-8')
- secret_key = self.secret_key.encode('utf-8')
- digest = hmac.new(secret_key, sig_data, hashlib.sha256).digest()
- return base64.b64encode(digest).decode('utf-8')
-
- def get_timestamp(self):
- """
- Returns the current timestamp in proper format.
- """
- return strftime("%Y-%m-%dT%H:%M:%SZ", gmtime())
-
- def enumerate_param(self, param, values):
- """
- Builds a dictionary of an enumerated parameter.
- Takes any iterable and returns a dictionary.
- ie.
- enumerate_param('MarketplaceIdList.Id', (123, 345, 4343))
- returns
- {
- MarketplaceIdList.Id.1: 123,
- MarketplaceIdList.Id.2: 345,
- MarketplaceIdList.Id.3: 4343
- }
- """
- params = {}
- if values is not None:
- if not param.endswith('.'):
- param = "%s." % param
- for num, value in enumerate(values):
- params['%s%d' % (param, (num + 1))] = value
- return params
-
-
-class Feeds(MWS):
- """ Amazon MWS Feeds API """
-
- ACCOUNT_TYPE = "Merchant"
-
- def submit_feed(self, feed, feed_type, marketplaceids=None,
- content_type="text/xml", purge='false'):
- """
- Uploads a feed ( xml or .tsv ) to the seller's inventory.
- Can be used for creating/updating products on Amazon.
- """
- data = dict(Action='SubmitFeed',
- FeedType=feed_type,
- PurgeAndReplace=purge)
- data.update(self.enumerate_param('MarketplaceIdList.Id.', marketplaceids))
- md = calc_md5(feed)
- return self.make_request(data, method="POST", body=feed,
- extra_headers={'Content-MD5': md, 'Content-Type': content_type})
-
- def get_feed_submission_list(self, feedids=None, max_count=None, feedtypes=None,
- processingstatuses=None, fromdate=None, todate=None):
- """
- Returns a list of all feed submissions submitted in the previous 90 days.
- That match the query parameters.
- """
-
- data = dict(Action='GetFeedSubmissionList',
- MaxCount=max_count,
- SubmittedFromDate=fromdate,
- SubmittedToDate=todate,)
- data.update(self.enumerate_param('FeedSubmissionIdList.Id', feedids))
- data.update(self.enumerate_param('FeedTypeList.Type.', feedtypes))
- data.update(self.enumerate_param('FeedProcessingStatusList.Status.', processingstatuses))
- return self.make_request(data)
-
- def get_submission_list_by_next_token(self, token):
- data = dict(Action='GetFeedSubmissionListByNextToken', NextToken=token)
- return self.make_request(data)
-
- def get_feed_submission_count(self, feedtypes=None, processingstatuses=None, fromdate=None, todate=None):
- data = dict(Action='GetFeedSubmissionCount',
- SubmittedFromDate=fromdate,
- SubmittedToDate=todate)
- data.update(self.enumerate_param('FeedTypeList.Type.', feedtypes))
- data.update(self.enumerate_param('FeedProcessingStatusList.Status.', processingstatuses))
- return self.make_request(data)
-
- def cancel_feed_submissions(self, feedids=None, feedtypes=None, fromdate=None, todate=None):
- data = dict(Action='CancelFeedSubmissions',
- SubmittedFromDate=fromdate,
- SubmittedToDate=todate)
- data.update(self.enumerate_param('FeedSubmissionIdList.Id.', feedids))
- data.update(self.enumerate_param('FeedTypeList.Type.', feedtypes))
- return self.make_request(data)
-
- def get_feed_submission_result(self, feedid):
- data = dict(Action='GetFeedSubmissionResult', FeedSubmissionId=feedid)
- return self.make_request(data)
-
-class Reports(MWS):
- """ Amazon MWS Reports API """
-
- ACCOUNT_TYPE = "Merchant"
-
- ## REPORTS ###
-
- def get_report(self, report_id):
- data = dict(Action='GetReport', ReportId=report_id)
- return self.make_request(data)
-
- def get_report_count(self, report_types=(), acknowledged=None, fromdate=None, todate=None):
- data = dict(Action='GetReportCount',
- Acknowledged=acknowledged,
- AvailableFromDate=fromdate,
- AvailableToDate=todate)
- data.update(self.enumerate_param('ReportTypeList.Type.', report_types))
- return self.make_request(data)
-
- def get_report_list(self, requestids=(), max_count=None, types=(), acknowledged=None,
- fromdate=None, todate=None):
- data = dict(Action='GetReportList',
- Acknowledged=acknowledged,
- AvailableFromDate=fromdate,
- AvailableToDate=todate,
- MaxCount=max_count)
- data.update(self.enumerate_param('ReportRequestIdList.Id.', requestids))
- data.update(self.enumerate_param('ReportTypeList.Type.', types))
- return self.make_request(data)
-
- def get_report_list_by_next_token(self, token):
- data = dict(Action='GetReportListByNextToken', NextToken=token)
- return self.make_request(data)
-
- def get_report_request_count(self, report_types=(), processingstatuses=(), fromdate=None, todate=None):
- data = dict(Action='GetReportRequestCount',
- RequestedFromDate=fromdate,
- RequestedToDate=todate)
- data.update(self.enumerate_param('ReportTypeList.Type.', report_types))
- data.update(self.enumerate_param('ReportProcessingStatusList.Status.', processingstatuses))
- return self.make_request(data)
-
- def get_report_request_list(self, requestids=(), types=(), processingstatuses=(),
- max_count=None, fromdate=None, todate=None):
- data = dict(Action='GetReportRequestList',
- MaxCount=max_count,
- RequestedFromDate=fromdate,
- RequestedToDate=todate)
- data.update(self.enumerate_param('ReportRequestIdList.Id.', requestids))
- data.update(self.enumerate_param('ReportTypeList.Type.', types))
- data.update(self.enumerate_param('ReportProcessingStatusList.Status.', processingstatuses))
- return self.make_request(data)
-
- def get_report_request_list_by_next_token(self, token):
- data = dict(Action='GetReportRequestListByNextToken', NextToken=token)
- return self.make_request(data)
-
- def request_report(self, report_type, start_date=None, end_date=None, marketplaceids=()):
- data = dict(Action='RequestReport',
- ReportType=report_type,
- StartDate=start_date,
- EndDate=end_date)
- data.update(self.enumerate_param('MarketplaceIdList.Id.', marketplaceids))
- return self.make_request(data)
-
- ### ReportSchedule ###
-
- def get_report_schedule_list(self, types=()):
- data = dict(Action='GetReportScheduleList')
- data.update(self.enumerate_param('ReportTypeList.Type.', types))
- return self.make_request(data)
-
- def get_report_schedule_count(self, types=()):
- data = dict(Action='GetReportScheduleCount')
- data.update(self.enumerate_param('ReportTypeList.Type.', types))
- return self.make_request(data)
-
-
-class Orders(MWS):
- """ Amazon Orders API """
-
- URI = "/Orders/2013-09-01"
- VERSION = "2013-09-01"
- NS = '{https://mws.amazonservices.com/Orders/2011-01-01}'
-
- def list_orders(self, marketplaceids, created_after=None, created_before=None, lastupdatedafter=None,
- lastupdatedbefore=None, orderstatus=(), fulfillment_channels=(),
- payment_methods=(), buyer_email=None, seller_orderid=None, max_results='100'):
-
- data = dict(Action='ListOrders',
- CreatedAfter=created_after,
- CreatedBefore=created_before,
- LastUpdatedAfter=lastupdatedafter,
- LastUpdatedBefore=lastupdatedbefore,
- BuyerEmail=buyer_email,
- SellerOrderId=seller_orderid,
- MaxResultsPerPage=max_results,
- )
- data.update(self.enumerate_param('OrderStatus.Status.', orderstatus))
- data.update(self.enumerate_param('MarketplaceId.Id.', marketplaceids))
- data.update(self.enumerate_param('FulfillmentChannel.Channel.', fulfillment_channels))
- data.update(self.enumerate_param('PaymentMethod.Method.', payment_methods))
- return self.make_request(data)
-
- def list_orders_by_next_token(self, token):
- data = dict(Action='ListOrdersByNextToken', NextToken=token)
- return self.make_request(data)
-
- def get_order(self, amazon_order_ids):
- data = dict(Action='GetOrder')
- data.update(self.enumerate_param('AmazonOrderId.Id.', amazon_order_ids))
- return self.make_request(data)
-
- def list_order_items(self, amazon_order_id):
- data = dict(Action='ListOrderItems', AmazonOrderId=amazon_order_id)
- return self.make_request(data)
-
- def list_order_items_by_next_token(self, token):
- data = dict(Action='ListOrderItemsByNextToken', NextToken=token)
- return self.make_request(data)
-
-
-class Products(MWS):
- """ Amazon MWS Products API """
-
- URI = '/Products/2011-10-01'
- VERSION = '2011-10-01'
- NS = '{http://mws.amazonservices.com/schema/Products/2011-10-01}'
-
- def list_matching_products(self, marketplaceid, query, contextid=None):
- """ Returns a list of products and their attributes, ordered by
- relevancy, based on a search query that you specify.
- Your search query can be a phrase that describes the product
- or it can be a product identifier such as a UPC, EAN, ISBN, or JAN.
- """
- data = dict(Action='ListMatchingProducts',
- MarketplaceId=marketplaceid,
- Query=query,
- QueryContextId=contextid)
- return self.make_request(data)
-
- def get_matching_product(self, marketplaceid, asins):
- """ Returns a list of products and their attributes, based on a list of
- ASIN values that you specify.
- """
- data = dict(Action='GetMatchingProduct', MarketplaceId=marketplaceid)
- data.update(self.enumerate_param('ASINList.ASIN.', asins))
- return self.make_request(data)
-
- def get_matching_product_for_id(self, marketplaceid, type, id):
- """ Returns a list of products and their attributes, based on a list of
- product identifier values (asin, sellersku, upc, ean, isbn and JAN)
- Added in Fourth Release, API version 2011-10-01
- """
- data = dict(Action='GetMatchingProductForId',
- MarketplaceId=marketplaceid,
- IdType=type)
- data.update(self.enumerate_param('IdList.Id', id))
- return self.make_request(data)
-
- def get_competitive_pricing_for_sku(self, marketplaceid, skus):
- """ Returns the current competitive pricing of a product,
- based on the SellerSKU and MarketplaceId that you specify.
- """
- data = dict(Action='GetCompetitivePricingForSKU', MarketplaceId=marketplaceid)
- data.update(self.enumerate_param('SellerSKUList.SellerSKU.', skus))
- return self.make_request(data)
-
- def get_competitive_pricing_for_asin(self, marketplaceid, asins):
- """ Returns the current competitive pricing of a product,
- based on the ASIN and MarketplaceId that you specify.
- """
- data = dict(Action='GetCompetitivePricingForASIN', MarketplaceId=marketplaceid)
- data.update(self.enumerate_param('ASINList.ASIN.', asins))
- return self.make_request(data)
-
- def get_lowest_offer_listings_for_sku(self, marketplaceid, skus, condition="Any", excludeme="False"):
- data = dict(Action='GetLowestOfferListingsForSKU',
- MarketplaceId=marketplaceid,
- ItemCondition=condition,
- ExcludeMe=excludeme)
- data.update(self.enumerate_param('SellerSKUList.SellerSKU.', skus))
- return self.make_request(data)
-
- def get_lowest_offer_listings_for_asin(self, marketplaceid, asins, condition="Any", excludeme="False"):
- data = dict(Action='GetLowestOfferListingsForASIN',
- MarketplaceId=marketplaceid,
- ItemCondition=condition,
- ExcludeMe=excludeme)
- data.update(self.enumerate_param('ASINList.ASIN.', asins))
- return self.make_request(data)
-
- def get_product_categories_for_sku(self, marketplaceid, sku):
- data = dict(Action='GetProductCategoriesForSKU',
- MarketplaceId=marketplaceid,
- SellerSKU=sku)
- return self.make_request(data)
-
- def get_product_categories_for_asin(self, marketplaceid, asin):
- data = dict(Action='GetProductCategoriesForASIN',
- MarketplaceId=marketplaceid,
- ASIN=asin)
- return self.make_request(data)
-
- def get_my_price_for_sku(self, marketplaceid, skus, condition=None):
- data = dict(Action='GetMyPriceForSKU',
- MarketplaceId=marketplaceid,
- ItemCondition=condition)
- data.update(self.enumerate_param('SellerSKUList.SellerSKU.', skus))
- return self.make_request(data)
-
- def get_my_price_for_asin(self, marketplaceid, asins, condition=None):
- data = dict(Action='GetMyPriceForASIN',
- MarketplaceId=marketplaceid,
- ItemCondition=condition)
- data.update(self.enumerate_param('ASINList.ASIN.', asins))
- return self.make_request(data)
-
-
-class Sellers(MWS):
- """ Amazon MWS Sellers API """
-
- URI = '/Sellers/2011-07-01'
- VERSION = '2011-07-01'
- NS = '{http://mws.amazonservices.com/schema/Sellers/2011-07-01}'
-
- def list_marketplace_participations(self):
- """
- Returns a list of marketplaces a seller can participate in and
- a list of participations that include seller-specific information in that marketplace.
- The operation returns only those marketplaces where the seller's account is in an active state.
- """
-
- data = dict(Action='ListMarketplaceParticipations')
- return self.make_request(data)
-
- def list_marketplace_participations_by_next_token(self, token):
- """
- Takes a "NextToken" and returns the same information as "list_marketplace_participations".
- Based on the "NextToken".
- """
- data = dict(Action='ListMarketplaceParticipations', NextToken=token)
- return self.make_request(data)
-
-#### Fulfillment APIs ####
-
-class InboundShipments(MWS):
- URI = "/FulfillmentInboundShipment/2010-10-01"
- VERSION = '2010-10-01'
-
- # To be completed
-
-
-class Inventory(MWS):
- """ Amazon MWS Inventory Fulfillment API """
-
- URI = '/FulfillmentInventory/2010-10-01'
- VERSION = '2010-10-01'
- NS = "{http://mws.amazonaws.com/FulfillmentInventory/2010-10-01}"
-
- def list_inventory_supply(self, skus=(), datetime=None, response_group='Basic'):
- """ Returns information on available inventory """
-
- data = dict(Action='ListInventorySupply',
- QueryStartDateTime=datetime,
- ResponseGroup=response_group,
- )
- data.update(self.enumerate_param('SellerSkus.member.', skus))
- return self.make_request(data, "POST")
-
- def list_inventory_supply_by_next_token(self, token):
- data = dict(Action='ListInventorySupplyByNextToken', NextToken=token)
- return self.make_request(data, "POST")
-
-
-class OutboundShipments(MWS):
- URI = "/FulfillmentOutboundShipment/2010-10-01"
- VERSION = "2010-10-01"
- # To be completed
-
-
-class Recommendations(MWS):
-
- """ Amazon MWS Recommendations API """
-
- URI = '/Recommendations/2013-04-01'
- VERSION = '2013-04-01'
- NS = "{https://mws.amazonservices.com/Recommendations/2013-04-01}"
-
- def get_last_updated_time_for_recommendations(self, marketplaceid):
- """
- Checks whether there are active recommendations for each category for the given marketplace, and if there are,
- returns the time when recommendations were last updated for each category.
- """
-
- data = dict(Action='GetLastUpdatedTimeForRecommendations',
- MarketplaceId=marketplaceid)
- return self.make_request(data, "POST")
-
- def list_recommendations(self, marketplaceid, recommendationcategory=None):
- """
- Returns your active recommendations for a specific category or for all categories for a specific marketplace.
- """
-
- data = dict(Action="ListRecommendations",
- MarketplaceId=marketplaceid,
- RecommendationCategory=recommendationcategory)
- return self.make_request(data, "POST")
-
- def list_recommendations_by_next_token(self, token):
- """
- Returns the next page of recommendations using the NextToken parameter.
- """
-
- data = dict(Action="ListRecommendationsByNextToken",
- NextToken=token)
- return self.make_request(data, "POST")
-
-class Finances(MWS):
- """ Amazon Finances API"""
- URI = '/Finances/2015-05-01'
- VERSION = '2015-05-01'
- NS = "{https://mws.amazonservices.com/Finances/2015-05-01}"
-
- def list_financial_events(self , posted_after=None, posted_before=None,
- amazon_order_id=None, max_results='100'):
-
- data = dict(Action='ListFinancialEvents',
- PostedAfter=posted_after,
- PostedBefore=posted_before,
- AmazonOrderId=amazon_order_id,
- MaxResultsPerPage=max_results,
- )
- return self.make_request(data)
diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.js b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.js
deleted file mode 100644
index f5ea804..0000000
--- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.js
+++ /dev/null
@@ -1,2 +0,0 @@
-// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.json b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.json
deleted file mode 100644
index 5a678e7..0000000
--- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.json
+++ /dev/null
@@ -1,237 +0,0 @@
-{
- "actions": [],
- "creation": "2018-07-31 05:51:41.357047",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "enable_amazon",
- "mws_credentials",
- "seller_id",
- "aws_access_key_id",
- "mws_auth_token",
- "secret_key",
- "column_break_4",
- "market_place_id",
- "region",
- "domain",
- "section_break_13",
- "company",
- "warehouse",
- "item_group",
- "price_list",
- "column_break_17",
- "customer_group",
- "territory",
- "customer_type",
- "market_place_account_group",
- "section_break_12",
- "after_date",
- "taxes_charges",
- "sync_products",
- "sync_orders",
- "column_break_10",
- "enable_sync",
- "max_retry_limit"
- ],
- "fields": [
- {
- "default": "0",
- "fieldname": "enable_amazon",
- "fieldtype": "Check",
- "label": "Enable Amazon"
- },
- {
- "fieldname": "mws_credentials",
- "fieldtype": "Section Break",
- "label": "MWS Credentials"
- },
- {
- "fieldname": "seller_id",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "Seller ID",
- "reqd": 1
- },
- {
- "fieldname": "aws_access_key_id",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "AWS Access Key ID",
- "reqd": 1
- },
- {
- "fieldname": "mws_auth_token",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "MWS Auth Token",
- "reqd": 1
- },
- {
- "fieldname": "secret_key",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "Secret Key",
- "reqd": 1
- },
- {
- "fieldname": "column_break_4",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "market_place_id",
- "fieldtype": "Data",
- "label": "Market Place ID",
- "reqd": 1
- },
- {
- "fieldname": "region",
- "fieldtype": "Select",
- "label": "Region",
- "options": "\nAE\nAU\nBR\nCA\nCN\nDE\nES\nFR\nIN\nJP\nIT\nMX\nUK\nUS",
- "reqd": 1
- },
- {
- "fieldname": "domain",
- "fieldtype": "Data",
- "label": "Domain",
- "reqd": 1
- },
- {
- "fieldname": "section_break_13",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "company",
- "fieldtype": "Link",
- "label": "Company",
- "options": "Company",
- "reqd": 1
- },
- {
- "fieldname": "warehouse",
- "fieldtype": "Link",
- "label": "Warehouse",
- "options": "Warehouse",
- "reqd": 1
- },
- {
- "fieldname": "item_group",
- "fieldtype": "Link",
- "label": "Item Group",
- "options": "Item Group",
- "reqd": 1
- },
- {
- "fieldname": "price_list",
- "fieldtype": "Link",
- "label": "Price List",
- "options": "Price List",
- "reqd": 1
- },
- {
- "fieldname": "column_break_17",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "customer_group",
- "fieldtype": "Link",
- "label": "Customer Group",
- "options": "Customer Group",
- "reqd": 1
- },
- {
- "fieldname": "territory",
- "fieldtype": "Link",
- "label": "Territory",
- "options": "Territory",
- "reqd": 1
- },
- {
- "fieldname": "customer_type",
- "fieldtype": "Select",
- "label": "Customer Type",
- "options": "Individual\nCompany",
- "reqd": 1
- },
- {
- "fieldname": "market_place_account_group",
- "fieldtype": "Link",
- "label": "Market Place Account Group",
- "options": "Account",
- "reqd": 1
- },
- {
- "fieldname": "section_break_12",
- "fieldtype": "Section Break"
- },
- {
- "description": "Amazon will synch data updated after this date",
- "fieldname": "after_date",
- "fieldtype": "Datetime",
- "label": "After Date",
- "reqd": 1
- },
- {
- "default": "0",
- "description": "Get financial breakup of Taxes and charges data by Amazon ",
- "fieldname": "taxes_charges",
- "fieldtype": "Check",
- "label": "Sync Taxes and Charges"
- },
- {
- "fieldname": "column_break_10",
- "fieldtype": "Column Break"
- },
- {
- "default": "3",
- "fieldname": "max_retry_limit",
- "fieldtype": "Int",
- "label": "Max Retry Limit"
- },
- {
- "description": "Always sync your products from Amazon MWS before synching the Orders details",
- "fieldname": "sync_products",
- "fieldtype": "Button",
- "label": "Sync Products",
- "options": "get_products_details"
- },
- {
- "description": "Click this button to pull your Sales Order data from Amazon MWS.",
- "fieldname": "sync_orders",
- "fieldtype": "Button",
- "label": "Sync Orders",
- "options": "get_order_details"
- },
- {
- "default": "0",
- "description": "Check this to enable a scheduled Daily synchronization routine via scheduler",
- "fieldname": "enable_sync",
- "fieldtype": "Check",
- "label": "Enable Scheduled Sync"
- }
- ],
- "issingle": 1,
- "links": [],
- "modified": "2020-04-07 14:26:20.174848",
- "modified_by": "Administrator",
- "module": "ERPNext Integrations",
- "name": "Amazon MWS Settings",
- "owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "print": 1,
- "read": 1,
- "role": "System Manager",
- "share": 1,
- "write": 1
- }
- ],
- "quick_entry": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.py
deleted file mode 100644
index c1f460f..0000000
--- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright (c) 2018, Frappe Technologies and contributors
-# For license information, please see license.txt
-
-
-import dateutil
-import frappe
-from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
-from frappe.model.document import Document
-
-from erpnext.erpnext_integrations.doctype.amazon_mws_settings.amazon_methods import get_orders
-
-
-class AmazonMWSSettings(Document):
- def validate(self):
- if self.enable_amazon == 1:
- self.enable_sync = 1
- setup_custom_fields()
- else:
- self.enable_sync = 0
-
- @frappe.whitelist()
- def get_products_details(self):
- if self.enable_amazon == 1:
- frappe.enqueue('erpnext.erpnext_integrations.doctype.amazon_mws_settings.amazon_methods.get_products_details')
-
- @frappe.whitelist()
- def get_order_details(self):
- if self.enable_amazon == 1:
- after_date = dateutil.parser.parse(self.after_date).strftime("%Y-%m-%d")
- frappe.enqueue('erpnext.erpnext_integrations.doctype.amazon_mws_settings.amazon_methods.get_orders', after_date=after_date)
-
-def schedule_get_order_details():
- mws_settings = frappe.get_doc("Amazon MWS Settings")
- if mws_settings.enable_sync and mws_settings.enable_amazon:
- after_date = dateutil.parser.parse(mws_settings.after_date).strftime("%Y-%m-%d")
- get_orders(after_date = after_date)
-
-def setup_custom_fields():
- custom_fields = {
- "Item": [dict(fieldname='amazon_item_code', label='Amazon Item Code',
- fieldtype='Data', insert_after='series', read_only=1, print_hide=1)],
- "Sales Order": [dict(fieldname='amazon_order_id', label='Amazon Order ID',
- fieldtype='Data', insert_after='title', read_only=1, print_hide=1)]
- }
-
- create_custom_fields(custom_fields)
diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/test_amazon_mws_settings.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/test_amazon_mws_settings.py
deleted file mode 100644
index 4be7960..0000000
--- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/test_amazon_mws_settings.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-
-import unittest
-
-
-class TestAmazonMWSSettings(unittest.TestCase):
- pass
diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/xml_utils.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/xml_utils.py
deleted file mode 100644
index d9dfc6f..0000000
--- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/xml_utils.py
+++ /dev/null
@@ -1,104 +0,0 @@
-"""
-Created on Tue Jun 26 15:42:07 2012
-
-Borrowed from https://github.com/timotheus/ebaysdk-python
-
-@author: pierre
-"""
-
-import re
-import xml.etree.ElementTree as ET
-
-
-class object_dict(dict):
- """object view of dict, you can
- >>> a = object_dict()
- >>> a.fish = 'fish'
- >>> a['fish']
- 'fish'
- >>> a['water'] = 'water'
- >>> a.water
- 'water'
- >>> a.test = {'value': 1}
- >>> a.test2 = object_dict({'name': 'test2', 'value': 2})
- >>> a.test, a.test2.name, a.test2.value
- (1, 'test2', 2)
- """
- def __init__(self, initd=None):
- if initd is None:
- initd = {}
- dict.__init__(self, initd)
-
- def __getattr__(self, item):
-
- try:
- d = self.__getitem__(item)
- except KeyError:
- return None
-
- if isinstance(d, dict) and 'value' in d and len(d) == 1:
- return d['value']
- else:
- return d
-
- # if value is the only key in object, you can omit it
- def __setstate__(self, item):
- return False
-
- def __setattr__(self, item, value):
- self.__setitem__(item, value)
-
- def getvalue(self, item, value=None):
- return self.get(item, {}).get('value', value)
-
-
-class xml2dict(object):
-
- def __init__(self):
- pass
-
- def _parse_node(self, node):
- node_tree = object_dict()
- # Save attrs and text, hope there will not be a child with same name
- if node.text:
- node_tree.value = node.text
- for (k, v) in node.attrib.items():
- k, v = self._namespace_split(k, object_dict({'value':v}))
- node_tree[k] = v
- #Save childrens
- for child in node.getchildren():
- tag, tree = self._namespace_split(child.tag,
- self._parse_node(child))
- if tag not in node_tree: # the first time, so store it in dict
- node_tree[tag] = tree
- continue
- old = node_tree[tag]
- if not isinstance(old, list):
- node_tree.pop(tag)
- node_tree[tag] = [old] # multi times, so change old dict to a list
- node_tree[tag].append(tree) # add the new one
-
- return node_tree
-
- def _namespace_split(self, tag, value):
- """
- Split the tag '{http://cs.sfsu.edu/csc867/myscheduler}patients'
- ns = http://cs.sfsu.edu/csc867/myscheduler
- name = patients
- """
- result = re.compile(r"\{(.*)\}(.*)").search(tag)
- if result:
- value.namespace, tag = result.groups()
-
- return (tag, value)
-
- def parse(self, file):
- """parse a xml file to a dict"""
- f = open(file, 'r')
- return self.fromstring(f.read())
-
- def fromstring(self, s):
- """parse a string"""
- t = ET.fromstring(s)
- root_tag, root_tree = self._namespace_split(t.tag, self._parse_node(t))
- return object_dict({root_tag: root_tree})
diff --git a/erpnext/erpnext_integrations/workspace/erpnext_integrations/erpnext_integrations.json b/erpnext/erpnext_integrations/workspace/erpnext_integrations/erpnext_integrations.json
index 45077aa..1f2619b 100644
--- a/erpnext/erpnext_integrations/workspace/erpnext_integrations/erpnext_integrations.json
+++ b/erpnext/erpnext_integrations/workspace/erpnext_integrations/erpnext_integrations.json
@@ -30,17 +30,6 @@
"type": "Link"
},
{
- "dependencies": "",
- "hidden": 0,
- "is_query_report": 0,
- "label": "Amazon MWS Settings",
- "link_count": 0,
- "link_to": "Amazon MWS Settings",
- "link_type": "DocType",
- "onboard": 0,
- "type": "Link"
- },
- {
"hidden": 0,
"is_query_report": 0,
"label": "Payments",
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index d99f23e..38fa691 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -333,7 +333,6 @@
"hourly": [
'erpnext.hr.doctype.daily_work_summary_group.daily_work_summary_group.trigger_emails',
"erpnext.accounts.doctype.subscription.subscription.process_all",
- "erpnext.erpnext_integrations.doctype.amazon_mws_settings.amazon_mws_settings.schedule_get_order_details",
"erpnext.accounts.doctype.gl_entry.gl_entry.rename_gle_sle_docs",
"erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.automatic_synchronization",
"erpnext.projects.doctype.project.project.hourly_reminder",
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index d300340..d104bc0 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -351,3 +351,4 @@
erpnext.patches.v13_0.shopping_cart_to_ecommerce
erpnext.patches.v13_0.update_disbursement_account
erpnext.patches.v13_0.update_reserved_qty_closed_wo
+erpnext.patches.v14_0.delete_amazon_mws_doctype
diff --git a/erpnext/patches/v12_0/rename_mws_settings_fields.py b/erpnext/patches/v12_0/rename_mws_settings_fields.py
deleted file mode 100644
index d5bf38d..0000000
--- a/erpnext/patches/v12_0/rename_mws_settings_fields.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright (c) 2020, Frappe and Contributors
-# License: GNU General Public License v3. See license.txt
-
-import frappe
-
-
-def execute():
- count = frappe.db.sql("SELECT COUNT(*) FROM `tabSingles` WHERE doctype='Amazon MWS Settings' AND field='enable_sync';")[0][0]
- if count == 0:
- frappe.db.sql("UPDATE `tabSingles` SET field='enable_sync' WHERE doctype='Amazon MWS Settings' AND field='enable_synch';")
-
- frappe.reload_doc("ERPNext Integrations", "doctype", "Amazon MWS Settings")
diff --git a/erpnext/patches/v14_0/delete_amazon_mws_doctype.py b/erpnext/patches/v14_0/delete_amazon_mws_doctype.py
new file mode 100644
index 0000000..525da6c
--- /dev/null
+++ b/erpnext/patches/v14_0/delete_amazon_mws_doctype.py
@@ -0,0 +1,5 @@
+import frappe
+
+
+def execute():
+ frappe.delete_doc("DocType", "Amazon MWS Settings", ignore_missing=True)
\ No newline at end of file