├── requirements.txt ├── lazada_erpnext_connector ├── patches.txt ├── config │ ├── __init__.py │ ├── desktop.py │ └── docs.py ├── www │ └── __init__.py ├── templates │ ├── __init__.py │ └── pages │ │ └── __init__.py ├── lazada_erpnext_connector │ ├── __init__.py │ ├── doctype │ │ ├── __init__.py │ │ ├── lazada_defaults │ │ │ ├── __init__.py │ │ │ ├── lazada_defaults.js │ │ │ ├── test_lazada_defaults.py │ │ │ ├── lazada_defaults.py │ │ │ └── lazada_defaults.json │ │ ├── lazada_settings │ │ │ ├── __init__.py │ │ │ ├── test_lazada_settings.py │ │ │ ├── lazada_settings.js │ │ │ ├── lazada_settings.json │ │ │ └── lazada_settings.py │ │ ├── shipment_provider │ │ │ ├── __init__.py │ │ │ ├── shipment_provider.js │ │ │ ├── test_shipment_provider.py │ │ │ ├── shipment_provider.py │ │ │ └── shipment_provider.json │ │ └── lazada_connector_error_log │ │ │ ├── __init__.py │ │ │ ├── lazada_connector_error_log.js │ │ │ ├── test_lazada_connector_error_log.py │ │ │ ├── lazada_connector_error_log.py │ │ │ └── lazada_connector_error_log.json │ ├── sales_order.py │ ├── stock_entry.py │ └── delivery_note.py ├── modules.txt ├── public │ ├── lazop │ │ ├── __init__.py │ │ ├── logs │ │ │ └── lazopsdk.log.2018-04-22 │ │ └── base.py │ └── js │ │ └── lazada.js ├── __init__.py ├── custom_scripts │ └── sales_order.js ├── hooks.py ├── utils │ └── lazada_utils.py └── fixtures │ └── custom_field.json ├── .gitignore ├── README.md ├── setup.py ├── MANIFEST.in └── LICENSE /requirements.txt: -------------------------------------------------------------------------------- 1 | frappe -------------------------------------------------------------------------------- /lazada_erpnext_connector/patches.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/config/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/www/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/templates/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/templates/pages/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/modules.txt: -------------------------------------------------------------------------------- 1 | Lazada ERPNext Connector -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/doctype/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/public/lazop/__init__.py: -------------------------------------------------------------------------------- 1 | from lazop.base import * -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/doctype/lazada_defaults/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/doctype/lazada_settings/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/doctype/shipment_provider/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/doctype/lazada_connector_error_log/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pyc 3 | *.egg-info 4 | *.swp 5 | tags 6 | lazada_erpnext_connector/docs/current -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Lazada ERPNext Connector 2 | 3 | Lazada Ecommerce Platform Integration with ERPNext 4 | 5 | #### License 6 | 7 | MIT 8 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | __version__ = '0.0.1' 5 | 6 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/doctype/lazada_defaults/lazada_defaults.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Raaj Tailor and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Lazada Defaults', { 5 | // refresh: function(frm) { 6 | 7 | // } 8 | }); 9 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/doctype/shipment_provider/shipment_provider.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Raaj Tailor and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Shipment Provider', { 5 | // refresh: function(frm) { 6 | 7 | // } 8 | }); 9 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/doctype/lazada_connector_error_log/lazada_connector_error_log.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Raaj Tailor and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Lazada Connector Error Log', { 5 | // refresh: function(frm) { 6 | 7 | // } 8 | }); 9 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/doctype/lazada_defaults/test_lazada_defaults.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Raaj Tailor and Contributors 3 | # See license.txt 4 | from __future__ import unicode_literals 5 | 6 | # import frappe 7 | import unittest 8 | 9 | class TestLazadaDefaults(unittest.TestCase): 10 | pass 11 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/doctype/lazada_settings/test_lazada_settings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Raaj Tailor and Contributors 3 | # See license.txt 4 | from __future__ import unicode_literals 5 | 6 | # import frappe 7 | import unittest 8 | 9 | class TestLazadaSettings(unittest.TestCase): 10 | pass 11 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/doctype/shipment_provider/test_shipment_provider.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Raaj Tailor and Contributors 3 | # See license.txt 4 | from __future__ import unicode_literals 5 | 6 | # import frappe 7 | import unittest 8 | 9 | class TestShipmentProvider(unittest.TestCase): 10 | pass 11 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/doctype/lazada_connector_error_log/test_lazada_connector_error_log.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Raaj Tailor and Contributors 3 | # See license.txt 4 | from __future__ import unicode_literals 5 | 6 | # import frappe 7 | import unittest 8 | 9 | class TestLazadaConnectorErrorLog(unittest.TestCase): 10 | pass 11 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/doctype/lazada_defaults/lazada_defaults.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Raaj Tailor and contributors 3 | # For license information, please see license.txt 4 | 5 | from __future__ import unicode_literals 6 | # import frappe 7 | from frappe.model.document import Document 8 | 9 | class LazadaDefaults(Document): 10 | pass 11 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/config/desktop.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | from frappe import _ 4 | 5 | def get_data(): 6 | return [ 7 | { 8 | "module_name": "Lazada ERPNext Connector", 9 | "color": "grey", 10 | "icon": "octicon octicon-file-directory", 11 | "type": "module", 12 | "label": _("Lazada ERPNext Connector") 13 | } 14 | ] 15 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/doctype/shipment_provider/shipment_provider.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Raaj Tailor and contributors 3 | # For license information, please see license.txt 4 | 5 | from __future__ import unicode_literals 6 | # import frappe 7 | from frappe.model.document import Document 8 | 9 | class ShipmentProvider(Document): 10 | pass 11 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/doctype/lazada_connector_error_log/lazada_connector_error_log.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Raaj Tailor and contributors 3 | # For license information, please see license.txt 4 | 5 | from __future__ import unicode_literals 6 | # import frappe 7 | from frappe.model.document import Document 8 | 9 | class LazadaConnectorErrorLog(Document): 10 | pass 11 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/config/docs.py: -------------------------------------------------------------------------------- 1 | """ 2 | Configuration for docs 3 | """ 4 | 5 | # source_link = "https://github.com/[org_name]/lazada_erpnext_connector" 6 | # docs_base_url = "https://[org_name].github.io/lazada_erpnext_connector" 7 | # headline = "App that does everything" 8 | # sub_heading = "Yes, you got that right the first time, everything" 9 | 10 | def get_context(context): 11 | context.brand_html = "Lazada ERPNext Connector" 12 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/custom_scripts/sales_order.js: -------------------------------------------------------------------------------- 1 | frappe.ui.form.on("Sales Order", { 2 | refresh: function(frm) { 3 | if(frm.doc.docstatus===1) { 4 | cur_frm.add_custom_button(__('Get ewaybill'), function(){ 5 | console.log("here") 6 | }); 7 | cur_frm.add_custom_button(__('Get Transaction Details'), function(){ 8 | frappe.call({ 9 | "method":"", 10 | 11 | }) 12 | }); 13 | } 14 | } 15 | }) -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from setuptools import setup, find_packages 3 | 4 | with open('requirements.txt') as f: 5 | install_requires = f.read().strip().split('\n') 6 | 7 | # get version from __version__ variable in lazada_erpnext_connector/__init__.py 8 | from lazada_erpnext_connector import __version__ as version 9 | 10 | setup( 11 | name='lazada_erpnext_connector', 12 | version=version, 13 | description='Lazada Ecommerce Platform Integration witH E', 14 | author='Raaj Tailor', 15 | author_email='tailorraj111@gmail.com', 16 | packages=find_packages(), 17 | zip_safe=False, 18 | include_package_data=True, 19 | install_requires=install_requires 20 | ) 21 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include MANIFEST.in 2 | include requirements.txt 3 | include *.json 4 | include *.md 5 | include *.py 6 | include *.txt 7 | recursive-include lazada_erpnext_connector *.css 8 | recursive-include lazada_erpnext_connector *.csv 9 | recursive-include lazada_erpnext_connector *.html 10 | recursive-include lazada_erpnext_connector *.ico 11 | recursive-include lazada_erpnext_connector *.js 12 | recursive-include lazada_erpnext_connector *.json 13 | recursive-include lazada_erpnext_connector *.md 14 | recursive-include lazada_erpnext_connector *.png 15 | recursive-include lazada_erpnext_connector *.py 16 | recursive-include lazada_erpnext_connector *.svg 17 | recursive-include lazada_erpnext_connector *.txt 18 | recursive-exclude lazada_erpnext_connector *.pyc -------------------------------------------------------------------------------- /lazada_erpnext_connector/public/lazop/logs/lazopsdk.log.2018-04-22: -------------------------------------------------------------------------------- 1 | 2018-04-22 15:53:49,044 - lazop.base - ERROR - 192.168.31.103^_^Darwin-17.5.0-x86_64-i386-64bit^_^https://auth.lazada.com/rest/auth/token/create?app_key=100627&sign_method=sha256×tamp=1524383629000&partner_id=lazop-sdk-python-20180422&code=0_1VD1csgglmJhiCks6GrblB0A2&sign=A3D8AD2A6F52D7F87769312EC0BF81AEDEF4CD5A3CB6A122F77B307112F0028E^_^InvalidCode^_^Invalid authorization code 2 | 192.168.31.103^_^Darwin-17.5.0-x86_64-i386-64bit^_^https://auth.lazada.com/rest/auth/token/create?app_key=100627&sign_method=sha256×tamp=1524383748000&partner_id=lazop-sdk-python-20180422&code=0_1VD1csgglmJhiCks6GrblB0A2&sign=520B38C698EF4AA678353C22D2E134AD1DF4005A88E025C69519AA38C89B42C4^_^InvalidCode^_^Invalid authorization code 3 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/doctype/lazada_settings/lazada_settings.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Raaj Tailor and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Lazada Settings', { 5 | // refresh: function(frm) { 6 | 7 | // } 8 | from_date:function(frm){ 9 | if(frm.doc.from_date && frm.doc.to_date){ 10 | check_date(frm.doc.from_date,frm.doc.to_date) 11 | } 12 | 13 | }, 14 | to_date:function(frm){ 15 | if(frm.doc.from_date && frm.doc.to_date){ 16 | check_date(frm.doc.from_date,frm.doc.to_date) 17 | } 18 | }, 19 | authorize_lazada:function(frm){ 20 | var auth_url = "https://auth.lazada.com/oauth/authorize?response_type=code&force_auth=true&redirect_uri="+frm.doc.callback_url+"&client_id="+frm.doc.api_key 21 | console.log(location.origin) 22 | window.open(auth_url); 23 | } 24 | }); 25 | 26 | function check_date(from_date,to_date){ 27 | if(from_date > to_date){ 28 | frappe.throw("Please Enter Correct From Date and To Date!") 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 ERPNext Apps 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/doctype/lazada_defaults/lazada_defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "creation": "2020-07-16 23:11:59.736177", 3 | "doctype": "DocType", 4 | "editable_grid": 1, 5 | "engine": "InnoDB", 6 | "field_order": [ 7 | "customer", 8 | "default_warehouse" 9 | ], 10 | "fields": [ 11 | { 12 | "fieldname": "customer", 13 | "fieldtype": "Link", 14 | "label": "Customer", 15 | "options": "Customer" 16 | }, 17 | { 18 | "fieldname": "default_warehouse", 19 | "fieldtype": "Link", 20 | "label": "Default Warehouse", 21 | "options": "Warehouse" 22 | } 23 | ], 24 | "issingle": 1, 25 | "modified": "2020-07-16 23:29:58.345986", 26 | "modified_by": "Administrator", 27 | "module": "Lazada ERPNext Connector", 28 | "name": "Lazada Defaults", 29 | "owner": "Administrator", 30 | "permissions": [ 31 | { 32 | "create": 1, 33 | "delete": 1, 34 | "email": 1, 35 | "print": 1, 36 | "read": 1, 37 | "role": "System Manager", 38 | "share": 1, 39 | "write": 1 40 | } 41 | ], 42 | "quick_entry": 1, 43 | "sort_field": "modified", 44 | "sort_order": "DESC", 45 | "track_changes": 1 46 | } -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/sales_order.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | import frappe 3 | from lazada_erpnext_connector.lazada_erpnext_connector.doctype.lazada_settings.lazada_settings import LazopClient,LazopRequest 4 | 5 | def submit(self,method): 6 | item_ids = [] 7 | for item in self.items: 8 | item_ids.append(item.order_item_id) 9 | client = LazopClient(frappe.db.get_value("Lazada Settings",None,"url"), frappe.db.get_value("Lazada Settings",None,"api_key") ,frappe.db.get_value("Lazada Settings",None,"api_secret")) 10 | request = LazopRequest('/order/rts') 11 | request.add_api_param('delivery_type', 'dropship') 12 | request.add_api_param('order_item_ids', str(item_ids)) 13 | request.add_api_param('shipment_provider', self.shipment_provider) 14 | request.add_api_param('tracking_number', '12345678') 15 | response = client.execute(request, frappe.db.get_value("Lazada Settings",None,"access_token")) 16 | # response = client.execute(request, frappe.db.get_value("Lazada Settings",None,"access_token")) 17 | frappe.msgprint(str(response.body)) 18 | 19 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/doctype/shipment_provider/shipment_provider.json: -------------------------------------------------------------------------------- 1 | { 2 | "autoname": "field:shipment_provider", 3 | "creation": "2020-07-31 15:50:01.002580", 4 | "doctype": "DocType", 5 | "editable_grid": 1, 6 | "engine": "InnoDB", 7 | "field_order": [ 8 | "shipment_provider", 9 | "is_cod" 10 | ], 11 | "fields": [ 12 | { 13 | "fieldname": "shipment_provider", 14 | "fieldtype": "Data", 15 | "label": "Shipment Provider ", 16 | "unique": 1 17 | }, 18 | { 19 | "default": "0", 20 | "fieldname": "is_cod", 21 | "fieldtype": "Check", 22 | "label": "Is COD" 23 | } 24 | ], 25 | "modified": "2020-07-31 16:10:11.307509", 26 | "modified_by": "Administrator", 27 | "module": "Lazada ERPNext Connector", 28 | "name": "Shipment Provider", 29 | "owner": "Administrator", 30 | "permissions": [ 31 | { 32 | "create": 1, 33 | "delete": 1, 34 | "email": 1, 35 | "export": 1, 36 | "print": 1, 37 | "read": 1, 38 | "report": 1, 39 | "role": "System Manager", 40 | "share": 1, 41 | "write": 1 42 | } 43 | ], 44 | "sort_field": "modified", 45 | "sort_order": "DESC", 46 | "track_changes": 1 47 | } -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/doctype/lazada_connector_error_log/lazada_connector_error_log.json: -------------------------------------------------------------------------------- 1 | { 2 | "autoname": "LER.####", 3 | "creation": "2020-07-03 17:40:11.130237", 4 | "doctype": "DocType", 5 | "editable_grid": 1, 6 | "engine": "InnoDB", 7 | "field_order": [ 8 | "call", 9 | "error_code", 10 | "error_log" 11 | ], 12 | "fields": [ 13 | { 14 | "fieldname": "call", 15 | "fieldtype": "Data", 16 | "in_list_view": 1, 17 | "label": "Call", 18 | "read_only": 1 19 | }, 20 | { 21 | "fieldname": "error_log", 22 | "fieldtype": "Text", 23 | "in_list_view": 1, 24 | "label": "Error Log", 25 | "read_only": 1 26 | }, 27 | { 28 | "fieldname": "error_code", 29 | "fieldtype": "Data", 30 | "in_list_view": 1, 31 | "label": "Error Code", 32 | "read_only": 1 33 | } 34 | ], 35 | "modified": "2020-07-03 18:08:45.959024", 36 | "modified_by": "Administrator", 37 | "module": "Lazada ERPNext Connector", 38 | "name": "Lazada Connector Error Log", 39 | "owner": "Administrator", 40 | "permissions": [ 41 | { 42 | "create": 1, 43 | "delete": 1, 44 | "email": 1, 45 | "export": 1, 46 | "print": 1, 47 | "read": 1, 48 | "report": 1, 49 | "role": "System Manager", 50 | "share": 1, 51 | "write": 1 52 | } 53 | ], 54 | "quick_entry": 1, 55 | "sort_field": "modified", 56 | "sort_order": "DESC", 57 | "track_changes": 1 58 | } -------------------------------------------------------------------------------- /lazada_erpnext_connector/public/js/lazada.js: -------------------------------------------------------------------------------- 1 | var jsElm = document.createElement("script"); 2 | jsElm.type = "application/javascript"; 3 | jsElm.src = "//laz-g-cdn.alicdn.com/sj/securesdk/0.0.3/securesdk_lzd_v1.js"; 4 | jsElm.id = "J_secure_sdk_v2"; 5 | jsElm.setAttribute("data-appkey", "120609") 6 | 7 | $( document ).ready(function() { 8 | var code = getUrlParameter('code'); 9 | if(code){ 10 | frappe.db.set_value("Lazada Settings",null,"code",code).then((res)=>{ 11 | if(res.message.code){ 12 | frappe.msgprint("Lazada is Authorized Sucessfully!") 13 | // window.location = window.location.href.split("?")[0]; 14 | window.location.replace(window.location.href.split("?")[0]); 15 | } 16 | }) 17 | } 18 | document.body.appendChild(jsElm); 19 | }); 20 | 21 | var getUrlParameter = function getUrlParameter(sParam) { 22 | var sPageURL = window.location.search.substring(1), 23 | sURLVariables = sPageURL.split('&'), 24 | sParameterName, 25 | i; 26 | 27 | for (i = 0; i < sURLVariables.length; i++) { 28 | sParameterName = sURLVariables[i].split('='); 29 | 30 | if (sParameterName[0] === sParam) { 31 | return sParameterName[1] === undefined ? true : decodeURIComponent(sParameterName[1]); 32 | } 33 | } 34 | }; -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/stock_entry.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | import frappe 3 | from lazada_erpnext_connector.lazada_erpnext_connector.doctype.lazada_settings.lazada_settings import LazopClient,LazopRequest 4 | 5 | def get_pw(doctype,field_name): 6 | docSettings = frappe.get_single(doctype) 7 | strPassword = docSettings.get_password(field_name) 8 | return strPassword 9 | 10 | api_secret = get_pw("Lazada Settings","api_secret") 11 | access_token = get_pw("Lazada Settings","access_token") 12 | 13 | def submit(self,method): 14 | # frappe.msgprint("in_submit") 15 | if self.update_on_lazada == 1: 16 | # frappe.msgprint("here") 17 | lazada_warehouse = frappe.db.get_value("Lazada Defaults",None,"default_warehouse") 18 | for item in self.items: 19 | if item.t_warehouse == lazada_warehouse: 20 | new_stock = frappe.get_value("Bin",{"warehouse":lazada_warehouse,"item_code":item.item_code},"actual_qty") 21 | # frappe.msgprint(str(new_stock)) 22 | set_stock_lazada(item.item_code,int(new_stock)) 23 | # item_ids.append(item.order_item_id) 24 | 25 | # # response = client.execute(request, frappe.db.get_value("Lazada Settings",None,"access_token")) 26 | # frappe.msgprint(str(response.body)) 27 | def set_stock_lazada(sku_id,qty): 28 | client = LazopClient(frappe.db.get_value("Lazada Settings",None,"url"), frappe.db.get_value("Lazada Settings",None,"api_key") ,api_secret) 29 | request = LazopRequest('/product/price_quantity/update') 30 | request.add_api_param('payload', """ 31 | 32 | 33 | 34 | {sku} 35 | {qty} 36 | 37 | 38 | 39 | """.format(sku=sku_id,qty=qty)) 40 | response = client.execute(request, access_token) 41 | if str(response.body['code']) == '0': 42 | frappe.msgprint("Stock has been updated to Lazada Seller!") 43 | else: 44 | # create_error_log('/order/rts',response.code,response.message) 45 | frappe.throw("Error Occured While updating Stock on Lazada. Error: {}".format(response.message)) 46 | # frappe.throw("Can't find Order with order id {}".format(self.lazada_order_id)) 47 | 48 | def create_error_log(call,error_code,error): 49 | doc = frappe.new_doc("Lazada Connector Error Log") 50 | doc.call=call 51 | doc.error_code=error_code 52 | doc.error_log=error 53 | doc.insert(ignore_permissions=True) 54 | 55 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/delivery_note.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | import frappe 3 | from lazada_erpnext_connector.lazada_erpnext_connector.doctype.lazada_settings.lazada_settings import LazopClient,LazopRequest 4 | 5 | 6 | def get_pw(doctype,field_name): 7 | docSettings = frappe.get_single(doctype) 8 | strPassword = docSettings.get_password(field_name) 9 | return strPassword 10 | 11 | api_secret = get_pw("Lazada Settings","api_secret") 12 | access_token = get_pw("Lazada Settings","access_token") 13 | 14 | def submit(self,method): 15 | if self.update_lazada_status: 16 | item_ids = [] 17 | for item in self.items: 18 | item_ids.append(item.order_item_id) 19 | client = LazopClient(frappe.db.get_value("Lazada Settings",None,"url"), frappe.db.get_value("Lazada Settings",None,"api_key") ,api_secret) 20 | request = LazopRequest('/order/rts') 21 | request.add_api_param('delivery_type', 'dropship') 22 | request.add_api_param('order_item_ids', str(item_ids)) 23 | request.add_api_param('shipment_provider', self.shipment_provider) 24 | request.add_api_param('tracking_number', '12345678') 25 | response = client.execute(request, access_token) 26 | # response = client.execute(request, frappe.db.get_value("Lazada Settings",None,"access_token")) 27 | if response.code == '0': 28 | frappe.msgprint("Sales Order is Ready to Ship!") 29 | else: 30 | create_error_log('/order/rts',response.code,response.message) 31 | frappe.msgprint("Error Occured While updating status on Lazada. Please Check Lazada Connector Error Log") 32 | frappe.msgprint(str(response.body)) 33 | def validate(self,method): 34 | if self.update_lazada_status: 35 | request = LazopRequest('/order/get','GET') 36 | request.add_api_param('order_id', str(self.lazada_order_id)) 37 | client = LazopClient(frappe.db.get_value("Lazada Settings",None,"url"), frappe.db.get_value("Lazada Settings",None,"api_key") ,api_secret) 38 | response = client.execute(request, access_token) 39 | # frappe.msgprint(str(response)) 40 | if str(response.body['code']) == '0': 41 | # frappe.msgprint(str(response.body['data']['statuses'])) 42 | if "canceled" in list(response.body['data']['statuses']): 43 | frappe.throw("This Sales Order id Cancelled in Lazada Seller!") 44 | else: 45 | # create_error_log('/order/rts',response.code,response.message) 46 | frappe.throw("Error Occured While creating Delivery Note. Error: {}".format(response.message)) 47 | # frappe.throw("Can't find Order with order id {}".format(self.lazada_order_id)) 48 | 49 | def create_error_log(call,error_code,error): 50 | doc = frappe.new_doc("Lazada Connector Error Log") 51 | doc.call=call 52 | doc.error_code=error_code 53 | doc.error_log=error 54 | doc.insert(ignore_permissions=True) 55 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/hooks.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | from . import __version__ as app_version 4 | 5 | app_name = "lazada_erpnext_connector" 6 | app_title = "Lazada ERPNext Connector" 7 | app_publisher = "Raaj Tailor" 8 | app_description = "Lazada Ecommerce Platform Integration witH E" 9 | app_icon = "octicon octicon-file-directory" 10 | app_color = "grey" 11 | app_email = "tailorraj111@gmail.com" 12 | app_license = "MIT" 13 | 14 | fixtures = ["Custom Field"] 15 | # Includes in 16 | # ------------------ 17 | 18 | # include js, css files in header of desk.html 19 | # app_include_css = "/assets/lazada_erpnext_connector/css/lazada_erpnext_connector.css" 20 | # app_include_js = "/assets/lazada_erpnext_connector/js/lazada_erpnext_connector.js" 21 | app_include_js = ["/assets/lazada_erpnext_connector/js/lazada.js"] 22 | 23 | # include js, css files in header of web template 24 | # web_include_css = "/assets/lazada_erpnext_connector/css/lazada_erpnext_connector.css" 25 | # web_include_js = "/assets/lazada_erpnext_connector/js/lazada_erpnext_connector.js" 26 | 27 | # include js in page 28 | # page_js = {"page" : "public/js/file.js"} 29 | doctype_js = { 30 | "Sales Order": ["custom_scripts/sales_order.js"], 31 | } 32 | # include js in doctype views 33 | # doctype_js = {"doctype" : "public/js/doctype.js"} 34 | # doctype_list_js = {"doctype" : "public/js/doctype_list.js"} 35 | # doctype_tree_js = {"doctype" : "public/js/doctype_tree.js"} 36 | # doctype_calendar_js = {"doctype" : "public/js/doctype_calendar.js"} 37 | 38 | # Home Pages 39 | # ---------- 40 | 41 | # application home page (will override Website Settings) 42 | # home_page = "login" 43 | 44 | # website user home page (by Role) 45 | # role_home_page = { 46 | # "Role": "home_page" 47 | # } 48 | 49 | # Website user home page (by function) 50 | # get_website_user_home_page = "lazada_erpnext_connector.utils.get_home_page" 51 | 52 | # Generators 53 | # ---------- 54 | 55 | # automatically create page for each record of this doctype 56 | # website_generators = ["Web Page"] 57 | 58 | # Installation 59 | # ------------ 60 | 61 | # before_install = "lazada_erpnext_connector.install.before_install" 62 | # after_install = "lazada_erpnext_connector.install.after_install" 63 | 64 | # Desk Notifications 65 | # ------------------ 66 | # See frappe.core.notifications.get_notification_config 67 | 68 | # notification_config = "lazada_erpnext_connector.notifications.get_notification_config" 69 | 70 | # Permissions 71 | # ----------- 72 | # Permissions evaluated in scripted ways 73 | 74 | # permission_query_conditions = { 75 | # "Event": "frappe.desk.doctype.event.event.get_permission_query_conditions", 76 | # } 77 | # 78 | # has_permission = { 79 | # "Event": "frappe.desk.doctype.event.event.has_permission", 80 | # } 81 | 82 | # Document Events 83 | # --------------- 84 | # Hook on document methods and events 85 | doc_events = { 86 | 87 | "Delivery Note" :{ 88 | "on_submit": "lazada_erpnext_connector.lazada_erpnext_connector.delivery_note.submit", 89 | "validate": "lazada_erpnext_connector.lazada_erpnext_connector.delivery_note.validate", 90 | 91 | } 92 | , 93 | "Stock Entry":{ 94 | "on_submit":"lazada_erpnext_connector.lazada_erpnext_connector.stock_entry.submit" 95 | } 96 | } 97 | # doc_events = { 98 | # "*": { 99 | # "on_update": "method", 100 | # "on_cancel": "method", 101 | # "on_trash": "method" 102 | # } 103 | # } 104 | 105 | # Scheduled Tasks 106 | # --------------- 107 | 108 | scheduler_events = { 109 | # "cron": { 110 | # "*/1 * * * *":[ 111 | # "lazada_erpnext_connector.lazada_erpnext_connector.doctype.lazada_settings.lazada_settings.get_refresh" 112 | # ] 113 | # } 114 | "daily": [ 115 | "lazada_erpnext_connector.lazada_erpnext_connector.doctype.lazada_settings.lazada_settings.get_refresh" 116 | ], 117 | "hourly": [ 118 | "lazada_erpnext_connector.lazada_erpnext_connector.doctype.lazada_settings.lazada_settings.get_orders" 119 | ] 120 | 121 | } 122 | 123 | # scheduler_events = { 124 | # "all": [ 125 | # "lazada_erpnext_connector.tasks.all" 126 | # ], 127 | # "daily": [ 128 | # "lazada_erpnext_connector.tasks.daily" 129 | # ], 130 | # "hourly": [ 131 | # "lazada_erpnext_connector.tasks.hourly" 132 | # ], 133 | # "weekly": [ 134 | # "lazada_erpnext_connector.tasks.weekly" 135 | # ] 136 | # "monthly": [ 137 | # "lazada_erpnext_connector.tasks.monthly" 138 | # ] 139 | # } 140 | 141 | # Testing 142 | # ------- 143 | 144 | # before_tests = "lazada_erpnext_connector.install.before_tests" 145 | 146 | # Overriding Methods 147 | # ------------------------------ 148 | # 149 | # override_whitelisted_methods = { 150 | # "frappe.desk.doctype.event.event.get_events": "lazada_erpnext_connector.event.get_events" 151 | # } 152 | # 153 | # each overriding function accepts a `data` argument; 154 | # generated from the base implementation of the doctype dashboard, 155 | # along with any modifications made in other Frappe apps 156 | # override_doctype_dashboards = { 157 | # "Task": "lazada_erpnext_connector.task.get_dashboard_data" 158 | # } 159 | 160 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/public/lazop/base.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | Created on 2018-03-21 4 | 5 | @author: xuteng.xt 6 | ''' 7 | 8 | import requests 9 | import time 10 | import hmac 11 | import hashlib 12 | import json 13 | import mimetypes 14 | import itertools 15 | import random 16 | import logging 17 | import os 18 | from os.path import expanduser 19 | import socket 20 | import platform 21 | 22 | # dir = os.getenv('HOME') 23 | dir = expanduser("~") 24 | isExists = os.path.exists(dir + "/logs") 25 | if not isExists: 26 | os.makedirs(dir + "/logs") 27 | logger = logging.getLogger(__name__) 28 | logger.setLevel(level = logging.ERROR) 29 | handler = logging.FileHandler(dir + "/logs/lazopsdk.log." + time.strftime("%Y-%m-%d", time.localtime())) 30 | handler.setLevel(logging.ERROR) 31 | # formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 32 | formatter = logging.Formatter('%(message)s') 33 | handler.setFormatter(formatter) 34 | logger.addHandler(handler) 35 | 36 | P_SDK_VERSION = "lazop-sdk-python-20181207" 37 | 38 | P_APPKEY = "app_key" 39 | P_ACCESS_TOKEN = "access_token" 40 | P_TIMESTAMP = "timestamp" 41 | P_SIGN = "sign" 42 | P_SIGN_METHOD = "sign_method" 43 | P_PARTNER_ID = "partner_id" 44 | P_DEBUG = "debug" 45 | 46 | P_CODE = 'code' 47 | P_TYPE = 'type' 48 | P_MESSAGE = 'message' 49 | P_REQUEST_ID = 'request_id' 50 | 51 | P_API_GATEWAY_URL_SG = 'https://api.lazada.sg/rest' 52 | P_API_GATEWAY_URL_MY = 'https://api.lazada.com.my/rest' 53 | P_API_GATEWAY_URL_VN = 'https://api.lazada.vn/rest' 54 | P_API_GATEWAY_URL_TH = 'https://api.lazada.co.th/rest' 55 | P_API_GATEWAY_URL_PH = 'https://api.lazada.com.ph/rest' 56 | P_API_GATEWAY_URL_ID = 'https://api.lazada.co.id/rest' 57 | P_API_AUTHORIZATION_URL = 'https://auth.lazada.com/rest' 58 | 59 | P_LOG_LEVEL_DEBUG = "DEBUG" 60 | P_LOG_LEVEL_INFO = "INFO" 61 | P_LOG_LEVEL_ERROR = "ERROR" 62 | 63 | 64 | def sign(secret,api, parameters): 65 | #=========================================================================== 66 | # @param secret 67 | # @param parameters 68 | #=========================================================================== 69 | sort_dict = sorted(parameters) 70 | 71 | parameters_str = "%s%s" % (api, 72 | str().join('%s%s' % (key, parameters[key]) for key in sort_dict)) 73 | 74 | h = hmac.new(secret.encode(encoding="utf-8"), parameters_str.encode(encoding="utf-8"), digestmod=hashlib.sha256) 75 | 76 | return h.hexdigest().upper() 77 | 78 | 79 | def mixStr(pstr): 80 | if(isinstance(pstr, str)): 81 | return pstr 82 | elif(isinstance(pstr, unicode)): 83 | return pstr.encode('utf-8') 84 | else: 85 | return str(pstr) 86 | 87 | def logApiError(appkey, sdkVersion, requestUrl, code, message): 88 | localIp = socket.gethostbyname(socket.gethostname()) 89 | platformType = platform.platform() 90 | logger.error("%s^_^%s^_^%s^_^%s^_^%s^_^%s^_^%s^_^%s" % ( 91 | appkey, sdkVersion, 92 | time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), 93 | localIp, platformType, requestUrl, code, message)) 94 | 95 | class LazopRequest(object): 96 | def __init__(self,api_pame,http_method = 'POST'): 97 | self._api_params = {} 98 | self._file_params = {} 99 | self._api_pame = api_pame 100 | self._http_method = http_method 101 | 102 | def add_api_param(self,key,value): 103 | self._api_params[key] = value 104 | 105 | def add_file_param(self,key,value): 106 | self._file_params[key] = value 107 | 108 | 109 | class LazopResponse(object): 110 | def __init__(self): 111 | self.type = None 112 | self.code = None 113 | self.message = None 114 | self.request_id = None 115 | self.body = None 116 | 117 | def __str__(self, *args, **kwargs): 118 | sb = "type=" + mixStr(self.type) +\ 119 | " code=" + mixStr(self.code) +\ 120 | " message=" + mixStr(self.message) +\ 121 | " requestId=" + mixStr(self.request_id) 122 | return sb 123 | 124 | class LazopClient(object): 125 | 126 | log_level = P_LOG_LEVEL_ERROR 127 | def __init__(self, server_url,app_key,app_secret,timeout=30): 128 | self._server_url = server_url 129 | self._app_key = app_key 130 | self._app_secret = app_secret 131 | self._timeout = timeout 132 | 133 | def execute(self, request,access_token = None): 134 | 135 | sys_parameters = { 136 | P_APPKEY: self._app_key, 137 | P_SIGN_METHOD: "sha256", 138 | P_TIMESTAMP: str(int(round(time.time()))) + '000', 139 | P_PARTNER_ID: P_SDK_VERSION 140 | } 141 | 142 | if(self.log_level == P_LOG_LEVEL_DEBUG): 143 | sys_parameters[P_DEBUG] = 'true' 144 | 145 | if(access_token): 146 | sys_parameters[P_ACCESS_TOKEN] = access_token 147 | 148 | application_parameter = request._api_params; 149 | 150 | sign_parameter = sys_parameters.copy() 151 | sign_parameter.update(application_parameter) 152 | 153 | sign_parameter[P_SIGN] = sign(self._app_secret,request._api_pame,sign_parameter) 154 | 155 | api_url = "%s%s" % (self._server_url,request._api_pame) 156 | 157 | full_url = api_url + "?"; 158 | for key in sign_parameter: 159 | full_url += key + "=" + str(sign_parameter[key]) + "&"; 160 | full_url = full_url[0:-1] 161 | 162 | try: 163 | if(request._http_method == 'POST' or len(request._file_params) != 0) : 164 | r = requests.post(api_url,sign_parameter,files=request._file_params, timeout=self._timeout) 165 | else: 166 | r = requests.get(api_url,sign_parameter, timeout=self._timeout) 167 | except Exception as err: 168 | logApiError(self._app_key, P_SDK_VERSION, full_url, "HTTP_ERROR", str(err)) 169 | raise err 170 | 171 | response = LazopResponse() 172 | 173 | jsonobj = r.json() 174 | 175 | if P_CODE in jsonobj: 176 | response.code = jsonobj[P_CODE] 177 | if P_TYPE in jsonobj: 178 | response.type = jsonobj[P_TYPE] 179 | if P_MESSAGE in jsonobj: 180 | response.message = jsonobj[P_MESSAGE] 181 | if P_REQUEST_ID in jsonobj: 182 | response.request_id = jsonobj[P_REQUEST_ID] 183 | 184 | if response.code is not None and response.code != "0": 185 | logApiError(self._app_key, P_SDK_VERSION, full_url, response.code, response.message) 186 | else: 187 | if(self.log_level == P_LOG_LEVEL_DEBUG or self.log_level == P_LOG_LEVEL_INFO): 188 | logApiError(self._app_key, P_SDK_VERSION, full_url, "", "") 189 | 190 | response.body = jsonobj 191 | 192 | return response 193 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/utils/lazada_utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | import frappe 3 | from frappe.model.document import Document 4 | import requests 5 | import time 6 | import hmac 7 | import hashlib 8 | import json 9 | import mimetypes 10 | import itertools 11 | import random 12 | import logging 13 | import os 14 | from os.path import expanduser 15 | import socket 16 | import platform 17 | from datetime import datetime 18 | from frappe.utils import now,getdate,add_days 19 | 20 | 21 | dir = expanduser("~") 22 | isExists = os.path.exists(dir + "/logs") 23 | if not isExists: 24 | os.makedirs(dir + "/logs") 25 | logger = logging.getLogger(__name__) 26 | logger.setLevel(level = logging.ERROR) 27 | handler = logging.FileHandler(dir + "/logs/lazopsdk.log." + time.strftime("%Y-%m-%d", time.localtime())) 28 | handler.setLevel(logging.ERROR) 29 | 30 | formatter = logging.Formatter('%(message)s') 31 | handler.setFormatter(formatter) 32 | logger.addHandler(handler) 33 | 34 | P_SDK_VERSION = "lazop-sdk-python-20181207" 35 | 36 | P_APPKEY = "app_key" 37 | P_ACCESS_TOKEN = "access_token" 38 | P_TIMESTAMP = "timestamp" 39 | P_SIGN = "sign" 40 | P_SIGN_METHOD = "sign_method" 41 | P_PARTNER_ID = "partner_id" 42 | P_DEBUG = "debug" 43 | 44 | P_CODE = 'code' 45 | P_TYPE = 'type' 46 | P_MESSAGE = 'message' 47 | P_REQUEST_ID = 'request_id' 48 | 49 | P_API_GATEWAY_URL_SG = 'https://api.lazada.sg/rest' 50 | P_API_GATEWAY_URL_MY = 'https://api.lazada.com.my/rest' 51 | P_API_GATEWAY_URL_VN = 'https://api.lazada.vn/rest' 52 | P_API_GATEWAY_URL_TH = 'https://api.lazada.co.th/rest' 53 | P_API_GATEWAY_URL_PH = 'https://api.lazada.com.ph/rest' 54 | P_API_GATEWAY_URL_ID = 'https://api.lazada.co.id/rest' 55 | P_API_AUTHORIZATION_URL = 'https://auth.lazada.com/rest' 56 | 57 | P_LOG_LEVEL_DEBUG = "DEBUG" 58 | P_LOG_LEVEL_INFO = "INFO" 59 | P_LOG_LEVEL_ERROR = "ERROR" 60 | 61 | 62 | def sign(secret,api, parameters): 63 | #=========================================================================== 64 | # @param secret 65 | # @param parameters 66 | #=========================================================================== 67 | sort_dict = sorted(parameters) 68 | 69 | parameters_str = "%s%s" % (api, 70 | str().join('%s%s' % (key, parameters[key]) for key in sort_dict)) 71 | 72 | h = hmac.new(secret.encode(encoding="utf-8"), parameters_str.encode(encoding="utf-8"), digestmod=hashlib.sha256) 73 | 74 | return h.hexdigest().upper() 75 | 76 | 77 | def mixStr(pstr): 78 | if(isinstance(pstr, str)): 79 | return pstr 80 | elif(isinstance(pstr, str)): 81 | return pstr.encode('utf-8') 82 | else: 83 | return str(pstr) 84 | 85 | def logApiError(appkey, sdkVersion, requestUrl, code, message): 86 | localIp = socket.gethostbyname(socket.gethostname()) 87 | platformType = platform.platform() 88 | logger.error("%s^_^%s^_^%s^_^%s^_^%s^_^%s^_^%s^_^%s" % ( 89 | appkey, sdkVersion, 90 | time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), 91 | localIp, platformType, requestUrl, code, message)) 92 | 93 | class LazopRequest(object): 94 | def __init__(self,api_pame,http_method = 'POST'): 95 | self._api_params = {} 96 | self._file_params = {} 97 | self._api_pame = api_pame 98 | self._http_method = http_method 99 | 100 | def add_api_param(self,key,value): 101 | self._api_params[key] = value 102 | 103 | def add_file_param(self,key,value): 104 | self._file_params[key] = value 105 | 106 | 107 | class LazopResponse(object): 108 | def __init__(self): 109 | self.type = None 110 | self.code = None 111 | self.message = None 112 | self.request_id = None 113 | self.body = None 114 | 115 | def __str__(self, *args, **kwargs): 116 | sb = "type=" + mixStr(self.type) +\ 117 | " code=" + mixStr(self.code) +\ 118 | " message=" + mixStr(self.message) +\ 119 | " requestId=" + mixStr(self.request_id) 120 | return sb 121 | 122 | class LazopClient(object): 123 | 124 | log_level = P_LOG_LEVEL_ERROR 125 | def __init__(self, server_url,app_key,app_secret,timeout=30): 126 | self._server_url = server_url 127 | self._app_key = app_key 128 | self._app_secret = app_secret 129 | self._timeout = timeout 130 | 131 | def execute(self, request,access_token = None): 132 | 133 | sys_parameters = { 134 | P_APPKEY: self._app_key, 135 | P_SIGN_METHOD: "sha256", 136 | P_TIMESTAMP: str(int(round(time.time()))) + '000', 137 | P_PARTNER_ID: P_SDK_VERSION 138 | } 139 | 140 | if(self.log_level == P_LOG_LEVEL_DEBUG): 141 | sys_parameters[P_DEBUG] = 'true' 142 | 143 | if(access_token): 144 | sys_parameters[P_ACCESS_TOKEN] = access_token 145 | 146 | application_parameter = request._api_params; 147 | 148 | sign_parameter = sys_parameters.copy() 149 | sign_parameter.update(application_parameter) 150 | 151 | sign_parameter[P_SIGN] = sign(self._app_secret,request._api_pame,sign_parameter) 152 | 153 | api_url = "%s%s" % (self._server_url,request._api_pame) 154 | 155 | full_url = api_url + "?"; 156 | for key in sign_parameter: 157 | full_url += key + "=" + str(sign_parameter[key]) + "&"; 158 | full_url = full_url[0:-1] 159 | 160 | try: 161 | if(request._http_method == 'POST' or len(request._file_params) != 0) : 162 | r = requests.post(api_url,sign_parameter,files=request._file_params, timeout=self._timeout) 163 | else: 164 | r = requests.get(api_url,sign_parameter, timeout=self._timeout) 165 | except Exception as err: 166 | logApiError(self._app_key, P_SDK_VERSION, full_url, "HTTP_ERROR", str(err)) 167 | raise err 168 | 169 | response = LazopResponse() 170 | 171 | jsonobj = r.json() 172 | 173 | if P_CODE in jsonobj: 174 | response.code = jsonobj[P_CODE] 175 | if P_TYPE in jsonobj: 176 | response.type = jsonobj[P_TYPE] 177 | if P_MESSAGE in jsonobj: 178 | response.message = jsonobj[P_MESSAGE] 179 | if P_REQUEST_ID in jsonobj: 180 | response.request_id = jsonobj[P_REQUEST_ID] 181 | 182 | if response.code is not None and response.code != "0": 183 | logApiError(self._app_key, P_SDK_VERSION, full_url, response.code, response.message) 184 | else: 185 | if(self.log_level == P_LOG_LEVEL_DEBUG or self.log_level == P_LOG_LEVEL_INFO): 186 | logApiError(self._app_key, P_SDK_VERSION, full_url, "", "") 187 | 188 | response.body = jsonobj 189 | 190 | return response -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/doctype/lazada_settings/lazada_settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "creation": "2020-06-30 17:18:08.240751", 3 | "doctype": "DocType", 4 | "editable_grid": 1, 5 | "engine": "InnoDB", 6 | "field_order": [ 7 | "url", 8 | "api_key", 9 | "api_secret", 10 | "column_break_4", 11 | "code", 12 | "callback_url", 13 | "authorize_lazada", 14 | "section_break_7", 15 | "access_token", 16 | "refresh_token", 17 | "column_break_10", 18 | "last_sync_access_token", 19 | "get_refresh_token", 20 | "get_access_token", 21 | "functions_call_section", 22 | "search_item", 23 | "created_after", 24 | "sync_limit", 25 | "column_break_14", 26 | "synced_items", 27 | "product_last_sync", 28 | "remaining_items", 29 | "total_lazada_item", 30 | "get_products", 31 | "section_break_15", 32 | "get_transactions", 33 | "column_break_18", 34 | "from_date", 35 | "to_date", 36 | "transaction_last_sync", 37 | "section_break_20", 38 | "get_orders", 39 | "column_break_22", 40 | "order_last_sync", 41 | "section_break_24", 42 | "get_category", 43 | "get_shipment_provider", 44 | "column_break_27", 45 | "last_shipment_provider_sync" 46 | ], 47 | "fields": [ 48 | { 49 | "fieldname": "api_key", 50 | "fieldtype": "Data", 51 | "label": "API Key" 52 | }, 53 | { 54 | "fieldname": "api_secret", 55 | "fieldtype": "Password", 56 | "label": "API Secret" 57 | }, 58 | { 59 | "fieldname": "callback_url", 60 | "fieldtype": "Data", 61 | "label": "Callback URL" 62 | }, 63 | { 64 | "fieldname": "code", 65 | "fieldtype": "Data", 66 | "label": "Code" 67 | }, 68 | { 69 | "fieldname": "url", 70 | "fieldtype": "Data", 71 | "label": "URL" 72 | }, 73 | { 74 | "fieldname": "access_token", 75 | "fieldtype": "Password", 76 | "label": "Access Token" 77 | }, 78 | { 79 | "fieldname": "refresh_token", 80 | "fieldtype": "Password", 81 | "label": "Refresh Token" 82 | }, 83 | { 84 | "fieldname": "get_access_token", 85 | "fieldtype": "Button", 86 | "label": "Get Access Token", 87 | "options": "get_access_token" 88 | }, 89 | { 90 | "fieldname": "get_products", 91 | "fieldtype": "Button", 92 | "label": "Get Products", 93 | "options": "get_products" 94 | }, 95 | { 96 | "fieldname": "get_refresh_token", 97 | "fieldtype": "Button", 98 | "label": "Get Refresh Token", 99 | "options": "get_refresh_token" 100 | }, 101 | { 102 | "fieldname": "get_orders", 103 | "fieldtype": "Button", 104 | "label": "Get Orders", 105 | "options": "get_orders" 106 | }, 107 | { 108 | "fieldname": "get_transactions", 109 | "fieldtype": "Button", 110 | "label": "Get Transactions", 111 | "options": "get_transactions" 112 | }, 113 | { 114 | "fieldname": "column_break_4", 115 | "fieldtype": "Column Break" 116 | }, 117 | { 118 | "fieldname": "functions_call_section", 119 | "fieldtype": "Section Break", 120 | "label": "Product Sync" 121 | }, 122 | { 123 | "fieldname": "last_sync_access_token", 124 | "fieldtype": "Datetime", 125 | "label": "Last Sync Access Token", 126 | "read_only": 1 127 | }, 128 | { 129 | "fieldname": "product_last_sync", 130 | "fieldtype": "Data", 131 | "label": "Product Last Sync", 132 | "read_only": 1 133 | }, 134 | { 135 | "fieldname": "order_last_sync", 136 | "fieldtype": "Data", 137 | "label": "Order Last Sync" 138 | }, 139 | { 140 | "fieldname": "get_category", 141 | "fieldtype": "Button", 142 | "hidden": 1, 143 | "label": "Get Category", 144 | "options": "get_category" 145 | }, 146 | { 147 | "fieldname": "get_shipment_provider", 148 | "fieldtype": "Button", 149 | "label": "Get Shipment Provider", 150 | "options": "get_shippment_pro" 151 | }, 152 | { 153 | "fieldname": "section_break_15", 154 | "fieldtype": "Section Break" 155 | }, 156 | { 157 | "fieldname": "column_break_14", 158 | "fieldtype": "Column Break" 159 | }, 160 | { 161 | "fieldname": "transaction_last_sync", 162 | "fieldtype": "Data", 163 | "label": "Transaction Last Sync", 164 | "read_only": 1 165 | }, 166 | { 167 | "fieldname": "column_break_18", 168 | "fieldtype": "Column Break" 169 | }, 170 | { 171 | "fieldname": "section_break_20", 172 | "fieldtype": "Section Break" 173 | }, 174 | { 175 | "fieldname": "column_break_22", 176 | "fieldtype": "Column Break" 177 | }, 178 | { 179 | "fieldname": "section_break_24", 180 | "fieldtype": "Section Break" 181 | }, 182 | { 183 | "fieldname": "column_break_27", 184 | "fieldtype": "Column Break" 185 | }, 186 | { 187 | "fieldname": "last_shipment_provider_sync", 188 | "fieldtype": "Data", 189 | "label": "Last Shipment Provider Sync", 190 | "read_only": 1 191 | }, 192 | { 193 | "fieldname": "section_break_7", 194 | "fieldtype": "Section Break" 195 | }, 196 | { 197 | "fieldname": "column_break_10", 198 | "fieldtype": "Column Break" 199 | }, 200 | { 201 | "fieldname": "from_date", 202 | "fieldtype": "Date", 203 | "label": "From Date" 204 | }, 205 | { 206 | "fieldname": "to_date", 207 | "fieldtype": "Date", 208 | "label": "To Date" 209 | }, 210 | { 211 | "fieldname": "authorize_lazada", 212 | "fieldtype": "Button", 213 | "label": "Authorize Lazada" 214 | }, 215 | { 216 | "description": "Minimum Sync limit 20 - Maximum Sync Limit 100", 217 | "fieldname": "sync_limit", 218 | "fieldtype": "Int", 219 | "label": "Sync Limit" 220 | }, 221 | { 222 | "fieldname": "synced_items", 223 | "fieldtype": "Int", 224 | "label": "Synced Items", 225 | "read_only": 1 226 | }, 227 | { 228 | "fieldname": "remaining_items", 229 | "fieldtype": "Int", 230 | "hidden": 1, 231 | "label": "Remaining Items" 232 | }, 233 | { 234 | "fieldname": "total_lazada_item", 235 | "fieldtype": "Int", 236 | "hidden": 1, 237 | "label": "Total Lazada Item" 238 | }, 239 | { 240 | "description": "Enter the Items You want to fetch from Lazada.\nNote: Enter Seller SKU of Item. Add Item in Comma-separated format.", 241 | "fieldname": "search_item", 242 | "fieldtype": "Small Text", 243 | "label": "Search Item" 244 | }, 245 | { 246 | "fieldname": "created_after", 247 | "fieldtype": "Date", 248 | "label": "Created After" 249 | } 250 | ], 251 | "issingle": 1, 252 | "modified": "2021-01-04 20:30:01.268501", 253 | "modified_by": "Administrator", 254 | "module": "Lazada ERPNext Connector", 255 | "name": "Lazada Settings", 256 | "owner": "Administrator", 257 | "permissions": [ 258 | { 259 | "create": 1, 260 | "delete": 1, 261 | "email": 1, 262 | "print": 1, 263 | "read": 1, 264 | "role": "System Manager", 265 | "share": 1, 266 | "write": 1 267 | } 268 | ], 269 | "quick_entry": 1, 270 | "sort_field": "modified", 271 | "sort_order": "DESC", 272 | "track_changes": 1 273 | } 274 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/fixtures/custom_field.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "allow_in_quick_entry": 0, 4 | "allow_on_submit": 0, 5 | "bold": 0, 6 | "collapsible": 0, 7 | "collapsible_depends_on": null, 8 | "columns": 0, 9 | "default": null, 10 | "depends_on": null, 11 | "description": null, 12 | "docstatus": 0, 13 | "doctype": "Custom Field", 14 | "dt": "Sales Order Item", 15 | "fetch_from": null, 16 | "fetch_if_empty": 0, 17 | "fieldname": "order_item_id", 18 | "fieldtype": "Data", 19 | "hidden": 0, 20 | "ignore_user_permissions": 0, 21 | "ignore_xss_filter": 0, 22 | "in_global_search": 0, 23 | "in_list_view": 0, 24 | "in_standard_filter": 0, 25 | "insert_after": "item_code", 26 | "label": "Order Item ID", 27 | "length": 0, 28 | "modified": "2020-07-31 21:48:22.672522", 29 | "name": "Sales Order Item-order_item_id", 30 | "no_copy": 0, 31 | "options": null, 32 | "parent": null, 33 | "parentfield": null, 34 | "parenttype": null, 35 | "permlevel": 0, 36 | "precision": "", 37 | "print_hide": 0, 38 | "print_hide_if_no_value": 0, 39 | "print_width": null, 40 | "read_only": 0, 41 | "report_hide": 0, 42 | "reqd": 0, 43 | "search_index": 0, 44 | "translatable": 0, 45 | "unique": 0, 46 | "width": null 47 | }, 48 | { 49 | "allow_in_quick_entry": 0, 50 | "allow_on_submit": 0, 51 | "bold": 0, 52 | "collapsible": 0, 53 | "collapsible_depends_on": null, 54 | "columns": 0, 55 | "default": null, 56 | "depends_on": null, 57 | "description": null, 58 | "docstatus": 0, 59 | "doctype": "Custom Field", 60 | "dt": "Item Group", 61 | "fetch_from": null, 62 | "fetch_if_empty": 0, 63 | "fieldname": "lazada_category_name", 64 | "fieldtype": "Data", 65 | "hidden": 0, 66 | "ignore_user_permissions": 0, 67 | "ignore_xss_filter": 0, 68 | "in_global_search": 0, 69 | "in_list_view": 0, 70 | "in_standard_filter": 0, 71 | "insert_after": "item_group_name", 72 | "label": "Lazada Category Name", 73 | "length": 0, 74 | "modified": "2020-07-29 23:59:06.752220", 75 | "name": "Item Group-lazada_category_name", 76 | "no_copy": 0, 77 | "options": null, 78 | "parent": null, 79 | "parentfield": null, 80 | "parenttype": null, 81 | "permlevel": 0, 82 | "precision": "", 83 | "print_hide": 0, 84 | "print_hide_if_no_value": 0, 85 | "print_width": null, 86 | "read_only": 0, 87 | "report_hide": 0, 88 | "reqd": 0, 89 | "search_index": 0, 90 | "translatable": 0, 91 | "unique": 0, 92 | "width": null 93 | }, 94 | { 95 | "allow_in_quick_entry": 0, 96 | "allow_on_submit": 0, 97 | "bold": 0, 98 | "collapsible": 0, 99 | "collapsible_depends_on": null, 100 | "columns": 0, 101 | "default": null, 102 | "depends_on": null, 103 | "description": null, 104 | "docstatus": 0, 105 | "doctype": "Custom Field", 106 | "dt": "Delivery Note Item", 107 | "fetch_from": null, 108 | "fetch_if_empty": 0, 109 | "fieldname": "order_item_id", 110 | "fieldtype": "Data", 111 | "hidden": 0, 112 | "ignore_user_permissions": 0, 113 | "ignore_xss_filter": 0, 114 | "in_global_search": 0, 115 | "in_list_view": 0, 116 | "in_standard_filter": 0, 117 | "insert_after": "item_code", 118 | "label": "Order Item ID", 119 | "length": 0, 120 | "modified": "2020-07-31 21:48:59.807423", 121 | "name": "Delivery Note Item-order_item_id", 122 | "no_copy": 0, 123 | "options": null, 124 | "parent": null, 125 | "parentfield": null, 126 | "parenttype": null, 127 | "permlevel": 0, 128 | "precision": "", 129 | "print_hide": 0, 130 | "print_hide_if_no_value": 0, 131 | "print_width": null, 132 | "read_only": 0, 133 | "report_hide": 0, 134 | "reqd": 0, 135 | "search_index": 0, 136 | "translatable": 0, 137 | "unique": 0, 138 | "width": null 139 | }, 140 | { 141 | "allow_in_quick_entry": 0, 142 | "allow_on_submit": 0, 143 | "bold": 0, 144 | "collapsible": 0, 145 | "collapsible_depends_on": null, 146 | "columns": 0, 147 | "default": null, 148 | "depends_on": null, 149 | "description": null, 150 | "docstatus": 0, 151 | "doctype": "Custom Field", 152 | "dt": "Sales Invoice Item", 153 | "fetch_from": null, 154 | "fetch_if_empty": 0, 155 | "fieldname": "order_item_id", 156 | "fieldtype": "Data", 157 | "hidden": 0, 158 | "ignore_user_permissions": 0, 159 | "ignore_xss_filter": 0, 160 | "in_global_search": 0, 161 | "in_list_view": 0, 162 | "in_standard_filter": 0, 163 | "insert_after": "item_code", 164 | "label": "Order Item ID", 165 | "length": 0, 166 | "modified": "2020-07-31 21:53:09.179524", 167 | "name": "Sales Invoice Item-order_item_id", 168 | "no_copy": 0, 169 | "options": null, 170 | "parent": null, 171 | "parentfield": null, 172 | "parenttype": null, 173 | "permlevel": 0, 174 | "precision": "", 175 | "print_hide": 0, 176 | "print_hide_if_no_value": 0, 177 | "print_width": null, 178 | "read_only": 0, 179 | "report_hide": 0, 180 | "reqd": 0, 181 | "search_index": 0, 182 | "translatable": 0, 183 | "unique": 0, 184 | "width": null 185 | }, 186 | { 187 | "allow_in_quick_entry": 0, 188 | "allow_on_submit": 0, 189 | "bold": 0, 190 | "collapsible": 0, 191 | "collapsible_depends_on": null, 192 | "columns": 0, 193 | "default": null, 194 | "depends_on": null, 195 | "description": null, 196 | "docstatus": 0, 197 | "doctype": "Custom Field", 198 | "dt": "Stock Entry", 199 | "fetch_from": null, 200 | "fetch_if_empty": 0, 201 | "fieldname": "update_on_lazada", 202 | "fieldtype": "Check", 203 | "hidden": 0, 204 | "ignore_user_permissions": 0, 205 | "ignore_xss_filter": 0, 206 | "in_global_search": 0, 207 | "in_list_view": 0, 208 | "in_standard_filter": 0, 209 | "insert_after": "stock_entry_type", 210 | "label": "Update On Lazada", 211 | "length": 0, 212 | "modified": "2020-08-02 11:46:44.842752", 213 | "name": "Stock Entry-update_on_lazada", 214 | "no_copy": 0, 215 | "options": null, 216 | "parent": null, 217 | "parentfield": null, 218 | "parenttype": null, 219 | "permlevel": 0, 220 | "precision": "", 221 | "print_hide": 0, 222 | "print_hide_if_no_value": 0, 223 | "print_width": null, 224 | "read_only": 0, 225 | "report_hide": 0, 226 | "reqd": 0, 227 | "search_index": 0, 228 | "translatable": 0, 229 | "unique": 0, 230 | "width": null 231 | }, 232 | { 233 | "allow_in_quick_entry": 0, 234 | "allow_on_submit": 0, 235 | "bold": 0, 236 | "collapsible": 0, 237 | "collapsible_depends_on": null, 238 | "columns": 0, 239 | "default": null, 240 | "depends_on": null, 241 | "description": null, 242 | "docstatus": 0, 243 | "doctype": "Custom Field", 244 | "dt": "Delivery Note", 245 | "fetch_from": null, 246 | "fetch_if_empty": 0, 247 | "fieldname": "shipment_provider", 248 | "fieldtype": "Link", 249 | "hidden": 0, 250 | "ignore_user_permissions": 0, 251 | "ignore_xss_filter": 0, 252 | "in_global_search": 0, 253 | "in_list_view": 0, 254 | "in_standard_filter": 0, 255 | "insert_after": "customer_name", 256 | "label": "Shipment Provider", 257 | "length": 0, 258 | "modified": "2020-07-31 16:17:32.606523", 259 | "name": "Delivery Note-shipment_provider", 260 | "no_copy": 0, 261 | "options": "Shipment Provider", 262 | "parent": null, 263 | "parentfield": null, 264 | "parenttype": null, 265 | "permlevel": 0, 266 | "precision": "", 267 | "print_hide": 0, 268 | "print_hide_if_no_value": 0, 269 | "print_width": null, 270 | "read_only": 0, 271 | "report_hide": 0, 272 | "reqd": 0, 273 | "search_index": 0, 274 | "translatable": 0, 275 | "unique": 0, 276 | "width": null 277 | }, 278 | { 279 | "allow_in_quick_entry": 0, 280 | "allow_on_submit": 0, 281 | "bold": 0, 282 | "collapsible": 0, 283 | "collapsible_depends_on": null, 284 | "columns": 0, 285 | "default": null, 286 | "depends_on": null, 287 | "description": null, 288 | "docstatus": 0, 289 | "doctype": "Custom Field", 290 | "dt": "Sales Order", 291 | "fetch_from": null, 292 | "fetch_if_empty": 0, 293 | "fieldname": "cash_direct_sales_name", 294 | "fieldtype": "Data", 295 | "hidden": 0, 296 | "ignore_user_permissions": 0, 297 | "ignore_xss_filter": 0, 298 | "in_global_search": 0, 299 | "in_list_view": 0, 300 | "in_standard_filter": 0, 301 | "insert_after": "customer_name", 302 | "label": "Lazada Customer Name", 303 | "length": 0, 304 | "modified": "2020-08-31 18:42:18.509040", 305 | "name": "Sales Order-cash_direct_sales_name", 306 | "no_copy": 0, 307 | "options": null, 308 | "parent": null, 309 | "parentfield": null, 310 | "parenttype": null, 311 | "permlevel": 0, 312 | "precision": "", 313 | "print_hide": 0, 314 | "print_hide_if_no_value": 0, 315 | "print_width": null, 316 | "read_only": 0, 317 | "report_hide": 0, 318 | "reqd": 0, 319 | "search_index": 0, 320 | "translatable": 0, 321 | "unique": 0, 322 | "width": null 323 | }, 324 | { 325 | "allow_in_quick_entry": 0, 326 | "allow_on_submit": 0, 327 | "bold": 0, 328 | "collapsible": 0, 329 | "collapsible_depends_on": null, 330 | "columns": 0, 331 | "default": null, 332 | "depends_on": null, 333 | "description": null, 334 | "docstatus": 0, 335 | "doctype": "Custom Field", 336 | "dt": "Delivery Note", 337 | "fetch_from": null, 338 | "fetch_if_empty": 0, 339 | "fieldname": "lazada_order_id", 340 | "fieldtype": "Data", 341 | "hidden": 0, 342 | "ignore_user_permissions": 0, 343 | "ignore_xss_filter": 0, 344 | "in_global_search": 0, 345 | "in_list_view": 0, 346 | "in_standard_filter": 0, 347 | "insert_after": "shipment_provider", 348 | "label": "Lazada Order ID", 349 | "length": 0, 350 | "modified": "2020-11-25 20:34:10.553211", 351 | "name": "Delivery Note-lazada_order_id", 352 | "no_copy": 0, 353 | "options": null, 354 | "parent": null, 355 | "parentfield": null, 356 | "parenttype": null, 357 | "permlevel": 0, 358 | "precision": "", 359 | "print_hide": 0, 360 | "print_hide_if_no_value": 0, 361 | "print_width": null, 362 | "read_only": 0, 363 | "report_hide": 0, 364 | "reqd": 0, 365 | "search_index": 0, 366 | "translatable": 0, 367 | "unique": 0, 368 | "width": null 369 | }, 370 | { 371 | "allow_in_quick_entry": 0, 372 | "allow_on_submit": 0, 373 | "bold": 0, 374 | "collapsible": 0, 375 | "collapsible_depends_on": null, 376 | "columns": 0, 377 | "default": null, 378 | "depends_on": null, 379 | "description": null, 380 | "docstatus": 0, 381 | "doctype": "Custom Field", 382 | "dt": "Sales Order", 383 | "fetch_from": null, 384 | "fetch_if_empty": 0, 385 | "fieldname": "lazada_order_id", 386 | "fieldtype": "Data", 387 | "hidden": 0, 388 | "ignore_user_permissions": 0, 389 | "ignore_xss_filter": 0, 390 | "in_global_search": 0, 391 | "in_list_view": 0, 392 | "in_standard_filter": 0, 393 | "insert_after": "order_type", 394 | "label": "Lazada Order ID", 395 | "length": 0, 396 | "modified": "2020-11-25 20:33:40.761037", 397 | "name": "Sales Order-lazada_order_id", 398 | "no_copy": 0, 399 | "options": null, 400 | "parent": null, 401 | "parentfield": null, 402 | "parenttype": null, 403 | "permlevel": 0, 404 | "precision": "", 405 | "print_hide": 0, 406 | "print_hide_if_no_value": 0, 407 | "print_width": null, 408 | "read_only": 1, 409 | "report_hide": 0, 410 | "reqd": 0, 411 | "search_index": 0, 412 | "translatable": 0, 413 | "unique": 0, 414 | "width": null 415 | }, 416 | { 417 | "allow_in_quick_entry": 0, 418 | "allow_on_submit": 0, 419 | "bold": 0, 420 | "collapsible": 0, 421 | "collapsible_depends_on": null, 422 | "columns": 0, 423 | "default": null, 424 | "depends_on": null, 425 | "description": null, 426 | "docstatus": 0, 427 | "doctype": "Custom Field", 428 | "dt": "Sales Invoice", 429 | "fetch_from": null, 430 | "fetch_if_empty": 0, 431 | "fieldname": "je_created", 432 | "fieldtype": "Check", 433 | "hidden": 0, 434 | "ignore_user_permissions": 0, 435 | "ignore_xss_filter": 0, 436 | "in_global_search": 0, 437 | "in_list_view": 0, 438 | "in_standard_filter": 0, 439 | "insert_after": "is_return", 440 | "label": "JE Created", 441 | "length": 0, 442 | "modified": "2020-08-21 19:57:35.636165", 443 | "name": "Sales Invoice-je_created", 444 | "no_copy": 0, 445 | "options": null, 446 | "parent": null, 447 | "parentfield": null, 448 | "parenttype": null, 449 | "permlevel": 0, 450 | "precision": "", 451 | "print_hide": 0, 452 | "print_hide_if_no_value": 0, 453 | "print_width": null, 454 | "read_only": 0, 455 | "report_hide": 0, 456 | "reqd": 0, 457 | "search_index": 0, 458 | "translatable": 0, 459 | "unique": 0, 460 | "width": null 461 | } 462 | ] 463 | -------------------------------------------------------------------------------- /lazada_erpnext_connector/lazada_erpnext_connector/doctype/lazada_settings/lazada_settings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Raaj Tailor and contributors 3 | # For license information, please see license.txt 4 | 5 | from __future__ import unicode_literals 6 | import frappe 7 | from frappe.model.document import Document 8 | import requests 9 | import time 10 | import hmac 11 | import hashlib 12 | import json 13 | import mimetypes 14 | import itertools 15 | import random 16 | import logging 17 | import os 18 | from os.path import expanduser 19 | import socket 20 | import platform 21 | from datetime import datetime 22 | from frappe.utils import now,getdate,add_days 23 | from frappe import enqueue 24 | from lazada_erpnext_connector.utils.lazada_utils import LazopClient,LazopRequest,LazopResponse 25 | 26 | 27 | class LazadaSettings(Document): 28 | 29 | def get_access_token(self): 30 | auth = Authentication() 31 | auth.get_access_token() 32 | def get_refresh_token(self): 33 | auth = Authentication() 34 | auth.get_refresh_token() 35 | def get_products(self): 36 | prod = Products() 37 | prod.create_erpnext_items() 38 | def get_orders(self): 39 | ord = Orders() 40 | ord.create_erpnext_order() 41 | def get_transactions(self): 42 | trans = Transaction() 43 | trans.create_erpnext_jornal_entry() 44 | def get_shippment_pro(self): 45 | ship_pro = Delivery() 46 | frappe.msgprint(str(ship_pro.get_shippment_provider())) 47 | 48 | # ***************************************************************************************************************** 49 | # Defaults Global Variables 50 | # ***************************************************************************************************************** 51 | 52 | def get_pw(doctype,field_name): 53 | docSettings = frappe.get_single(doctype) 54 | strPassword = docSettings.get_password(field_name) 55 | return strPassword 56 | 57 | # try: 58 | # # api_key = frappe.db.get_value("Lazada Settings",None,"api_key") 59 | # # api_secret = get_pw("Lazada Settings","api_secret") 60 | # # access_token = get_pw("Lazada Settings","access_token") 61 | # # url = frappe.db.get_value("Lazada Settings",None,"url") 62 | # except Exception as e: 63 | # print(e) 64 | # pass 65 | 66 | # ***************************************************************************************************************** 67 | # API Functions Classes 68 | # ***************************************************************************************************************** 69 | 70 | class Products(LazadaSettings): 71 | def __init__(self): 72 | self.api_key = frappe.db.get_value("Lazada Settings",None,"api_key") 73 | self.api_secret = get_pw("Lazada Settings","api_secret") 74 | self.url = frappe.db.get_value("Lazada Settings",None,"url") 75 | self.last_sync_prod = frappe.db.get_value("Lazada Settings",None,"product_last_sync") 76 | self.sync_limit = frappe.db.get_value("Lazada Settings",None,"sync_limit") 77 | self.synced_items = frappe.db.get_value("Lazada Settings",None,"synced_items") 78 | self.created_after = frappe.db.get_value("Lazada Settings",None,"created_after") 79 | self.search_item = frappe.db.get_value("Lazada Settings",None,"search_item") 80 | self.access_token = get_pw("Lazada Settings","access_token") 81 | 82 | def get_all_products(self,limit,offset): 83 | client = LazopClient(self.url, self.api_key ,self.api_secret) 84 | request = LazopRequest('/products/get','GET') 85 | request.add_api_param('filter', 'all') 86 | request.add_api_param('offset', offset) 87 | request.add_api_param('limit', limit) 88 | 89 | if self.search_item: 90 | sku_list = json.dumps(self.search_item.split(",")) 91 | frappe.msgprint(str(sku_list)) 92 | request.add_api_param('sku_seller_list', sku_list) 93 | 94 | if self.created_after: 95 | created_after = datetime.strptime(str(self.created_after),"%Y-%m-%d").isoformat() 96 | request.add_api_param('create_after', created_after) 97 | 98 | response = client.execute(request, self.access_token) 99 | if response.code != '0': 100 | # frappe.msgprint("Call is not sucessful") 101 | create_error_log('/products/get',response.code,response.message) 102 | frappe.msgprint("There is some error while creating Items. Please Check Lazada Error Log!") 103 | return False 104 | else: 105 | # frappe.msgprint(str(response.code)) 106 | # frappe.msgprint(str(response.body)) 107 | if bool(response.body['data']): 108 | return (response.body['data']['total_products'],response.body) 109 | else: 110 | frappe.msgprint("No Item Found to Sync!") 111 | frappe.db.set_value("Lazada Settings",None,"synced_items",0) 112 | return False 113 | 114 | # frappe.msgprint(str(bool(response.body['data']))) 115 | 116 | 117 | 118 | 119 | def create_erpnext_items(self): 120 | lazada_product = self.get_all_products(self.sync_limit,self.synced_items) 121 | # frappe.throw(str(lazada_product)) 122 | if lazada_product: 123 | # frappe.db.set_value("Lazada Settings",None,"total_lazada_item",int(lazada_product[0])) 124 | products = lazada_product[1] 125 | 126 | if products and products['data']: 127 | count = 0 128 | for product in products['data']['products']: 129 | for sku in product['skus']: 130 | count = count + 1 131 | if not frappe.db.exists("Item", sku['SellerSku']): 132 | if not frappe.db.exists("Item Group", product['primary_category']): 133 | item_group = frappe.new_doc("Item Group") 134 | item_group.item_group_name = str(product['primary_category']) 135 | item_group.is_group = 0 136 | item_group.parent_item_group = "Lazada Item Category" 137 | item_group.insert(ignore_permissions=True) 138 | 139 | item_doc = frappe.new_doc("Item") 140 | item_doc.item_code = str(sku['SellerSku']) 141 | item_doc.item_name = product['attributes']['name'] 142 | if 'short_description' in (product['attributes'].keys()): 143 | item_doc.description = product['attributes']['short_description'] 144 | item_doc.item_group = product['primary_category'] 145 | item_doc.stock_uom = "Nos" 146 | item_doc.is_stock_item = 1 147 | item_doc.valuation_rate = 1 148 | item_doc.opening_stock = sku['quantity'] 149 | item_doc.insert(ignore_permissions=True) 150 | item_doc.item_defaults = [{ 151 | "company":frappe.db.get_value("Global Defaults",None,"default_company"), 152 | "default_warehouse":frappe.db.get_value("Lazada Defaults",None,"default_warehouse") 153 | }] 154 | frappe.msgprint(str(item_doc.name)+" Created!") 155 | frappe.db.set_value("Lazada Settings",None,"product_last_sync",datetime.now().replace(microsecond=0).isoformat()) 156 | 157 | else: 158 | frappe.msgprint("Item {} is already created".format(sku['SellerSku'])) 159 | frappe.db.set_value("Lazada Settings",None,"synced_items",int(frappe.db.get_value("Lazada Settings",None,"synced_items")) + count) 160 | # frappe.db.set_value("Lazada Settings",None,"remaining_items",int(frappe.db.get_value("Lazada Settings",None,"total_lazada_item")) -int(frappe.db.get_value("Lazada Settings",None,"synced_items"))) 161 | 162 | # else: 163 | # frappe.msgprint("There is some error while creating Items. Please Check Lazada Error Log!") 164 | 165 | class Delivery(object): 166 | def __init__(self): 167 | self.api_key = frappe.db.get_value("Lazada Settings",None,"api_key") 168 | self.api_secret = get_pw("Lazada Settings","api_secret") 169 | self.access_token = get_pw("Lazada Settings","access_token") 170 | self.url = frappe.db.get_value("Lazada Settings",None,"url") 171 | # pass 172 | def get_shippment_provider(self): 173 | client = LazopClient(self.url, self.api_key ,self.api_secret) 174 | request = LazopRequest('/shipment/providers/get','GET') 175 | 176 | response = client.execute(request, self.access_token) 177 | data = response.body['data']['shipment_providers'] 178 | for ship in data: 179 | shipment_provider = { 180 | "doctype":"Shipment Provider", 181 | "shipment_provider":ship['name'], 182 | "is_cod":ship['cod'] 183 | } 184 | if not frappe.db.exists("Shipment Provider", ship['name']): 185 | frappe.get_doc(shipment_provider).insert(ignore_permissions=True) 186 | frappe.db.set_value("Lazada Settings",None,"last_shipment_provider_sync",datetime.now().replace(microsecond=0).isoformat()) 187 | return response.body 188 | # print(response.type) 189 | # print(response.body) 190 | 191 | class Orders(object): 192 | def __init__(self): 193 | self.api_key = frappe.db.get_value("Lazada Settings",None,"api_key") 194 | self.api_secret = get_pw("Lazada Settings","api_secret") 195 | self.access_token = get_pw("Lazada Settings","access_token") 196 | self.default_customer = frappe.db.get_value("Lazada Defaults",None,"customer") 197 | self.default_warehouse = frappe.db.get_value("Lazada Defaults",None,"default_warehouse") 198 | self.last_sync = frappe.db.get_value("Lazada Settings",None,"order_last_sync") 199 | self.url = frappe.db.get_value("Lazada Settings",None,"url") 200 | 201 | def get_all_orders(self): 202 | client = LazopClient(self.url, self.api_key ,self.api_secret) 203 | request = LazopRequest('/orders/get','GET') 204 | if self.last_sync: 205 | request.add_api_param('created_after', self.last_sync) 206 | request.add_api_param('status', 'pending') 207 | request.add_api_param('limit', 99) 208 | request.add_api_param('sort_direction', 'DESC') 209 | # frappe.msgprint(str(access_token)) 210 | response = client.execute(request,self.access_token) 211 | # frappe.msgprint(str(response.type)) 212 | # frappe.msgprint(str(response.body)) 213 | if response.code != '0': 214 | # frappe.msgprint("Call is not sucessful") 215 | create_error_log('/orders/get',response.code,response.message) 216 | return False 217 | else: 218 | # frappe.msgprint(str(response.code)) 219 | # frappe.msgprint(str(response.body)) 220 | return response.body 221 | 222 | 223 | def get_order_items(self,order_id): 224 | client = LazopClient(self.url, self.api_key ,self.api_secret) 225 | request = LazopRequest('/orders/items/get','GET') 226 | request.add_api_param('order_ids', order_id) 227 | response = client.execute(request, self.access_token) 228 | if response.code != '0': 229 | # frappe.msgprint("Call is not sucessful") 230 | create_error_log('/orders/items/get',response.code,response.message) 231 | return False 232 | else: 233 | # frappe.msgprint(str(response.code)) 234 | # frappe.msgprint(str(response)) 235 | # res_body = response.body 236 | return response.body 237 | # return response.body 238 | 239 | 240 | 241 | def create_erpnext_order(self): 242 | orders_list = self.get_all_orders() 243 | orders_ids=[] 244 | if orders_list: 245 | for order in orders_list['data']['orders']: 246 | orders_ids.append(str(order['order_id'])) 247 | order_items = self.get_order_items(str(orders_ids)) 248 | if order_items: 249 | for order in orders_list['data']['orders']: 250 | for order_item in order_items['data']: 251 | if order['order_id'] == order_item['order_id']: 252 | items = [] 253 | for item in order_item['order_items']: 254 | items.append({ 255 | "item_code":item['sku'], 256 | "item_name":item["name"], 257 | "rate":item['item_price'], 258 | "qty":1, 259 | "order_item_id":item['order_item_id'] 260 | }) 261 | sales_order = { 262 | "doctype":"Sales Order", 263 | "customer":self.default_customer, 264 | "set_warehouse":self.default_warehouse, 265 | "transaction_date":getdate(datetime.strptime(order['created_at'], "%Y-%m-%d %H:%M:%S %z")), 266 | "delivery_date":add_days(getdate(datetime.strptime(order['created_at'], "%Y-%m-%d %H:%M:%S %z")),2), 267 | "lazada_order_id":order['order_id'], 268 | "po_no":order['order_number'], 269 | "items":items, 270 | "cash_direct_sales_name":order['address_shipping']['first_name'], 271 | "order_type":"Sales"} 272 | if not frappe.db.exists("Sales Order", frappe.db.get_value("Sales Order",{"po_no":order['order_number']},"name")): 273 | # frappe.msgprint(str(items)) 274 | # frappe.msgprint(str(sales_order)) 275 | res_doc = frappe.get_doc(sales_order).insert(ignore_permissions=True) 276 | frappe.msgprint("Sales Order Created {}".format(res_doc.name)) 277 | 278 | frappe.db.set_value("Lazada Settings",None,"order_last_sync",datetime.now().replace(microsecond=0).isoformat()) 279 | 280 | class OrdersDoc(object): 281 | def __init__(self): 282 | self.api_key = frappe.db.get_value("Lazada Settings",None,"api_key") 283 | self.api_secret = get_pw("Lazada Settings","api_secret") 284 | self.access_token = get_pw("Lazada Settings","access_token") 285 | self.url = frappe.db.get_value("Lazada Settings",None,"url") 286 | 287 | def get_oreder_doc(self,order_item_ids): 288 | client = LazopClient(self.url, self.api_key ,self.api_secret) 289 | request = LazopRequest('/order/document/get','GET') 290 | request.add_api_param('doc_type', 'invoice') 291 | request.add_api_param('order_item_ids', order_item_ids) 292 | 293 | response = client.execute(request, self.access_token) 294 | # frappe.msgprint(str(response.type)) 295 | # frappe.msgprint(str(response.body)) 296 | return response.body 297 | 298 | def attach_to_erpnext_invoice(self): 299 | pass 300 | 301 | class Transaction(object): 302 | def __init__(self): 303 | self.api_key = frappe.db.get_value("Lazada Settings",None,"api_key") 304 | self.api_secret = get_pw("Lazada Settings","api_secret") 305 | self.access_token = get_pw("Lazada Settings","access_token") 306 | self.company = frappe.db.get_value("Global Defaults",None,"default_company") 307 | self.cash_account = frappe.db.get_value("Company",self.company,"default_cash_account") 308 | self.receivalble = frappe.db.get_value("Company",self.company,"default_receivable_account") 309 | self.customer = frappe.db.get_value("Lazada Defaults",None,"customer") 310 | self.last_transc_sync = frappe.db.get_value("Lazada Defaults",None,"transaction_last_sync") 311 | self.from_date = frappe.db.get_value("Lazada Settings",None,"from_date") 312 | self.to_date = frappe.db.get_value("Lazada Settings",None,"to_date") 313 | self.url = frappe.db.get_value("Lazada Settings",None,"url") 314 | 315 | def get_all_transaction(self): 316 | # frappe.msgprint(str(self.from_date)) 317 | # frappe.throw(str(self.to_date)) 318 | if not self.from_date or not self.to_date: 319 | frappe.throw("Please Enter From Date and To Date to get Transaction.") 320 | client = LazopClient(self.url, self.api_key ,self.api_secret) 321 | request = LazopRequest('/finance/transaction/detail/get','GET') 322 | request.add_api_param('trans_type', '13') 323 | request.add_api_param('end_time', str(self.to_date)) 324 | request.add_api_param('start_time',str(self.from_date)) 325 | response = client.execute(request, self.access_token) 326 | # frappe.msgprint(str(response.type)) 327 | # frappe.msgprint(str(response.body)) 328 | return response.body 329 | 330 | def create_erpnext_jornal_entry(self): 331 | transaction_list = self.get_all_transaction() 332 | account_entry = [] 333 | invoice_list = [] 334 | 335 | for transc in transaction_list['data']: 336 | sales_invoice = frappe.db.get_value("Sales Invoice",{"po_no":transc["order_no"],"je_created":0},"name") 337 | if sales_invoice: 338 | account_entry.append({ 339 | "account":self.receivalble, 340 | "party_type":"Customer", 341 | "party":self.customer, 342 | "credit_in_account_currency":float(transc['amount']), 343 | "reference_type":"Sales Invoice", 344 | "reference_name":sales_invoice 345 | }) 346 | account_entry.append({ 347 | "account":self.cash_account, 348 | "debit_in_account_currency":float(transc['amount']), 349 | 350 | }) 351 | invoice_list.append(sales_invoice) 352 | 353 | if len(account_entry) != 0: 354 | frappe.msgprint(str(account_entry)) 355 | self.creat_je(account_entry,invoice_list) 356 | frappe.db.set_value("Lazada Settings",None,"transaction_last_sync",datetime.now().replace(microsecond=0).isoformat()) 357 | 358 | def creat_je(self,account_entry,invoice_list): 359 | je_doc ={ 360 | "doctype":"Journal Entry", 361 | "voucher_type":"Journal Entry", 362 | "posting_date":frappe.utils.now(), 363 | "accounts":account_entry 364 | } 365 | frappe.get_doc(je_doc).insert(ignore_permissions=True) 366 | 367 | for inv in invoice_list: 368 | frappe.db.set_value("Sales Invoice",inv,"je_created",1) 369 | frappe.msgprint("Payment Created For Invoice {}".format(inv)) 370 | 371 | class Authentication(object): 372 | def __init__(self): 373 | self.api_key = frappe.db.get_value("Lazada Settings",None,"api_key") 374 | self.api_secret = get_pw("Lazada Settings","api_secret") 375 | self.url = frappe.db.get_value("Lazada Settings",None,"url") 376 | # self.access_token = get_pw("Lazada Settings","access_token") 377 | self.callback_url = frappe.db.get_value("Lazada Settings",None,"callback_url") 378 | 379 | 380 | def get_code(self): 381 | res = frappe.db.get_value("Lazada Settings",None,"code") 382 | # res = requests.get("https://auth.lazada.com/oauth/authorize?response_type=code&force_auth=true&redirect_uri={call_back_url}&client_id={appkey}".format(call_back_url=self.callback_url,appkey=self.api_key)) 383 | # frappe.msgprint(str(res)) 384 | return res 385 | 386 | def get_access_token(self): 387 | client = LazopClient("https://auth.lazada.com/rest", self.api_key ,self.api_secret) 388 | request = LazopRequest('/auth/token/create') 389 | request.add_api_param("code", self.get_code()) 390 | response = client.execute(request) 391 | # frappe.msgprint(str(response.body)) 392 | if response.body['code'] != '0': 393 | frappe.msgprint("Access token is Already Generated. Please Use Refresh Token Button!") 394 | else: 395 | frappe.db.set_value("Lazada Settings",None,"access_token",response.body["access_token"]) 396 | frappe.db.set_value("Lazada Settings",None,"refresh_token",response.body['refresh_token']) 397 | frappe.msgprint("Access Token has been successfully Genrated. Please Reload Page.") 398 | 399 | def get_refresh_token(self): 400 | refresh_t = get_pw("Lazada Settings","refresh_token") 401 | client = LazopClient("https://auth.lazada.com/rest", self.api_key ,self.api_secret) 402 | request = LazopRequest('/auth/token/refresh') 403 | request.add_api_param("refresh_token", refresh_t) 404 | response = client.execute(request) 405 | # frappe.msgprint(str(response.body)) 406 | # frappe.msgprint(str(now())) 407 | if response.body['code'] == '0': 408 | frappe.db.set_value("Lazada Settings",None,"access_token",response.body["access_token"]) 409 | frappe.db.set_value("Lazada Settings",None,"refresh_token",response.body['refresh_token']) 410 | frappe.db.set_value("Lazada Settings",None,"last_sync_access_token",now()) 411 | frappe.msgprint("Access Token has been refreshed successfully. Please Reload Page!") 412 | else: 413 | frappe.msgprint("Error Occured While Refreshing Acces token.") 414 | 415 | # ********************************************************************************************************************* 416 | # FunctionS called By Scheduler 417 | # ********************************************************************************************************************* 418 | 419 | def create_error_log(call,error_code,error): 420 | doc = frappe.new_doc("Lazada Connector Error Log") 421 | doc.call=call 422 | doc.error_code=error_code 423 | doc.error_log=error 424 | doc.insert(ignore_permissions=True) 425 | 426 | frappe.whitelist() 427 | def get_refresh(): 428 | auth = Authentication() 429 | auth.get_refresh_token() 430 | 431 | frappe.whitelist() 432 | def get_orders(): 433 | ord = Orders() 434 | ord.create_erpnext_order() 435 | 436 | frappe.whitelist() 437 | def get_items_back(): 438 | prod = Products() 439 | prod.create_erpnext_items() 440 | 441 | 442 | 443 | --------------------------------------------------------------------------------