├── .gitignore ├── MANIFEST.in ├── README.md ├── license.txt ├── requirements.txt ├── setup.py └── whatsapp_integration ├── __init__.py ├── api.py ├── config ├── __init__.py ├── desktop.py └── docs.py ├── fixtures └── custom_fields.json ├── hooks.py ├── modules.txt ├── patches.txt ├── public └── js │ ├── moneky_whatsapp.js │ └── sms_center.js ├── templates ├── __init__.py └── pages │ └── __init__.py └── whatsapp_integration ├── __init__.py └── doctype ├── __init__.py └── whatsapp_settings ├── __init__.py ├── test_whatsapp_settings.py ├── whatsapp_settings.js ├── whatsapp_settings.json └── whatsapp_settings.py /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pyc 3 | *.egg-info 4 | *.swp 5 | tags 6 | whatsapp_integration/docs/current -------------------------------------------------------------------------------- /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 whatsapp_integration *.css 8 | recursive-include whatsapp_integration *.csv 9 | recursive-include whatsapp_integration *.html 10 | recursive-include whatsapp_integration *.ico 11 | recursive-include whatsapp_integration *.js 12 | recursive-include whatsapp_integration *.json 13 | recursive-include whatsapp_integration *.md 14 | recursive-include whatsapp_integration *.png 15 | recursive-include whatsapp_integration *.py 16 | recursive-include whatsapp_integration *.svg 17 | recursive-include whatsapp_integration *.txt 18 | recursive-exclude whatsapp_integration *.pyc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Whatsapp Integration for ERPNext 2 | 3 | ### Whatsapp Settings doctype 4 | ![Captura de Pantalla 2019-11-05 a la(s) 14 55 26](https://user-images.githubusercontent.com/46027152/68233033-22e81080-ffdd-11e9-915f-6ecf946b634c.png) 5 | 6 | ### New button "Send Whatsapp" in SMS Center 7 | ![Captura de Pantalla 2019-11-05 a la(s) 14 56 16](https://user-images.githubusercontent.com/46027152/68233034-22e81080-ffdd-11e9-9ce6-64c048586e09.png) 8 | 9 | ### New option "Whatsapp" (and Attach Document Print) in "Send SMS" dialog 10 | ![66226881-405e4d80-e6b2-11e9-8692-c72e69eedf8c](https://user-images.githubusercontent.com/46027152/68233035-22e81080-ffdd-11e9-9a64-93cc4d5635ab.png) 11 | 12 | ## Installation Guide 13 | First you have to get the app: 14 | ```shell 15 | bench get-app git@github.com:fproldan/erpnext_whatsapp.git 16 | ``` 17 | Then, you should double check for the requirements to be ready: 18 | ```shell 19 | bench update --requirements 20 | bench build 21 | ``` 22 | And for the last step, you should install the app in you site: 23 | ```shell 24 | bench --site SITE_NAME install-app whatsapp_integration 25 | ``` 26 | 27 | ## Whatsapp for Business limitations 28 | - WhatsApp requires that your application implement [explicit user opt-ins](https://developers.facebook.com/docs/whatsapp/guides/opt-in/) to deliver messages over WhatsApp . 29 | - You always should start the comunication with a template message aproved by Whatsapp. To read more about templates, click [here](https://developers.facebook.com/docs/whatsapp/message-templates/creation/). 30 | - After the client sends you a message, you have 24hs to send whatever you want (not only template messages). 31 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | License: MIT -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | frappe 2 | twilio -------------------------------------------------------------------------------- /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 whatsapp_integration/__init__.py 8 | from whatsapp_integration import __version__ as version 9 | 10 | setup( 11 | name='whatsapp_integration', 12 | version=version, 13 | description='Integrations for Whatsapp for Business', 14 | author='Diamo', 15 | author_email='contacto@diamo.com.ar', 16 | packages=find_packages(), 17 | zip_safe=False, 18 | include_package_data=True, 19 | install_requires=install_requires 20 | ) 21 | -------------------------------------------------------------------------------- /whatsapp_integration/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | __version__ = '0.0.1' 5 | 6 | -------------------------------------------------------------------------------- /whatsapp_integration/api.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2017, Diamo and contributors 3 | # For license information, please see license.txt 4 | from __future__ import unicode_literals 5 | 6 | import frappe 7 | from frappe import _ 8 | from twilio.rest import Client 9 | from six import string_types 10 | import frappe 11 | from frappe import _ 12 | from frappe.utils.print_format import download_pdf 13 | from frappe.core.doctype.sms_settings.sms_settings import validate_receiver_nos 14 | 15 | 16 | @frappe.whitelist(allow_guest=True) 17 | def get_pdf_for_whatsapp(doctype, name, key): 18 | doc = frappe.get_doc(doctype, name) 19 | if not key == doc.get_signature(): 20 | return 403 21 | download_pdf(doctype, name, format=None, doc=None, no_letterhead=0) 22 | 23 | 24 | def get_url_for_whatsapp(doctype, name): 25 | doc = frappe.get_doc(doctype, name) 26 | return "{url}/api/method/whatsapp_integration.api.get_pdf_for_whatsapp?doctype={doctype}&name={name}&key={key}".format( 27 | url=frappe.utils.get_url(), 28 | doctype=doctype, 29 | name=name, 30 | key=doc.get_signature() 31 | ).replace(" ", "%20") 32 | 33 | 34 | @frappe.whitelist() 35 | def send_whatsapp(receiver_list, msg, doctype="", name=""): 36 | import json 37 | if isinstance(receiver_list, string_types) and doctype != "SMS Center": 38 | receiver_list = json.loads(receiver_list) 39 | if not isinstance(receiver_list, list): 40 | receiver_list = [receiver_list] 41 | elif doctype == "SMS Center": 42 | sms = frappe.get_doc("SMS Center") 43 | sms.receiver_list = receiver_list 44 | receiver_list = sms.get_receiver_nos() 45 | 46 | receiver_list = validate_receiver_nos(receiver_list) 47 | 48 | wp_settings = frappe.get_doc("Whatsapp Settings") 49 | client = Client(wp_settings.twilio_sid, wp_settings.twilio_token) 50 | errors = [] 51 | 52 | message_kwargs = { 53 | "from_": 'whatsapp:{}'.format(wp_settings.wp_number), 54 | "body": msg 55 | } 56 | 57 | attachment_kwargs = {} 58 | if doctype and doctype != "SMS Center": 59 | attachment_kwargs = { 60 | "from_": 'whatsapp:{}'.format(wp_settings.wp_number), 61 | "media_url": get_url_for_whatsapp(doctype, name), 62 | "body": "{name}.pdf".format(name=name) 63 | } 64 | 65 | for rec in receiver_list: 66 | if attachment_kwargs: 67 | attachment_kwargs.update({"to": 'whatsapp:{}'.format(rec)}) 68 | resp = _send_whatsapp(attachment_kwargs, client) 69 | if not resp: 70 | errors.append(rec) 71 | continue 72 | 73 | if not msg: 74 | continue 75 | 76 | message_kwargs.update({"to": 'whatsapp:{}'.format(rec)}) 77 | resp = _send_whatsapp(message_kwargs, client) 78 | if not resp: 79 | errors.append(rec) 80 | 81 | if errors: 82 | frappe.msgprint(_("The message wasn't correctly delivered to: {}".format(", ".join(errors)))) 83 | 84 | return "The message was correctly delivered" 85 | 86 | 87 | def _send_whatsapp(message_dict, client): 88 | response = client.messages.create(**message_dict) 89 | return response.sid 90 | -------------------------------------------------------------------------------- /whatsapp_integration/config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netmanthan/erpnext_whatsapp/1b6c7957c6340833742b67365c2627e57fd3646f/whatsapp_integration/config/__init__.py -------------------------------------------------------------------------------- /whatsapp_integration/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": "Whatsapp Integration", 9 | "color": "grey", 10 | "icon": "octicon octicon-file-directory", 11 | "type": "module", 12 | "label": _("Whatsapp Integration") 13 | } 14 | ] 15 | -------------------------------------------------------------------------------- /whatsapp_integration/config/docs.py: -------------------------------------------------------------------------------- 1 | """ 2 | Configuration for docs 3 | """ 4 | 5 | # source_link = "https://github.com/[org_name]/whatsapp_integration" 6 | # docs_base_url = "https://[org_name].github.io/whatsapp_integration" 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 = "Whatsapp Integration" 12 | -------------------------------------------------------------------------------- /whatsapp_integration/fixtures/custom_fields.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "doctype": "DocField", 4 | "name": "2f371686381", 5 | "creation": "2013-01-10 16:34:22.000000", 6 | "modified": "2019-11-05 20:20:21.537934", 7 | "modified_by": "Administrator", 8 | "owner": "Administrator", 9 | "docstatus": 0, 10 | "parent": "SMS Center", 11 | "parentfield": "fields", 12 | "parenttype": "DocType", 13 | "idx": 14, 14 | "fieldname": "send_whatsapp", 15 | "label": "Send Whatsapp", 16 | "oldfieldname": null, 17 | "fieldtype": "Button", 18 | "oldfieldtype": null, 19 | "options": "", 20 | "search_index": 0, 21 | "hidden": 0, 22 | "set_only_once": 0, 23 | "allow_in_quick_entry": 0, 24 | "print_hide": 0, 25 | "report_hide": 0, 26 | "reqd": 0, 27 | "bold": 0, 28 | "in_global_search": 0, 29 | "collapsible": 0, 30 | "unique": 0, 31 | "no_copy": 0, 32 | "allow_on_submit": 0, 33 | "show_preview_popup": 0, 34 | "trigger": null, 35 | "collapsible_depends_on": null, 36 | "depends_on": null, 37 | "permlevel": 0, 38 | "ignore_user_permissions": 0, 39 | "width": null, 40 | "print_width": null, 41 | "columns": 0, 42 | "default": null, 43 | "description": null, 44 | "in_list_view": 0, 45 | "fetch_if_empty": 0, 46 | "in_filter": 0, 47 | "remember_last_selected_value": 0, 48 | "ignore_xss_filter": 0, 49 | "print_hide_if_no_value": 0, 50 | "allow_bulk_edit": 0, 51 | "in_standard_filter": 0, 52 | "in_preview": 0, 53 | "read_only": 0, 54 | "precision": null, 55 | "length": 0, 56 | "translatable": 0, 57 | "fetch_from": null 58 | } 59 | ] 60 | -------------------------------------------------------------------------------- /whatsapp_integration/hooks.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | from . import __version__ as app_version 4 | 5 | app_name = "whatsapp_integration" 6 | app_title = "Whatsapp Integration" 7 | app_publisher = "Diamo" 8 | app_description = "Integrations for Whatsapp for Business" 9 | app_icon = "octicon octicon-file-directory" 10 | app_color = "grey" 11 | app_email = "contacto@diamo.com.ar" 12 | app_license = "MIT" 13 | 14 | 15 | doctype_js = { 16 | "SMS Center": "public/js/sms_center.js" 17 | } 18 | 19 | app_include_js = "/assets/whatsapp_integration/js/moneky_whatsapp.js" 20 | 21 | # Includes in 22 | # ------------------ 23 | 24 | # include js, css files in header of desk.html 25 | # app_include_css = "/assets/whatsapp_integration/css/whatsapp_integration.css" 26 | # app_include_js = "/assets/whatsapp_integration/js/whatsapp_integration.js" 27 | 28 | # include js, css files in header of web template 29 | # web_include_css = "/assets/whatsapp_integration/css/whatsapp_integration.css" 30 | # web_include_js = "/assets/whatsapp_integration/js/whatsapp_integration.js" 31 | 32 | # include js in page 33 | # page_js = {"page" : "public/js/file.js"} 34 | 35 | # include js in doctype views 36 | # doctype_js = {"doctype" : "public/js/doctype.js"} 37 | # doctype_list_js = {"doctype" : "public/js/doctype_list.js"} 38 | # doctype_tree_js = {"doctype" : "public/js/doctype_tree.js"} 39 | # doctype_calendar_js = {"doctype" : "public/js/doctype_calendar.js"} 40 | 41 | # Home Pages 42 | # ---------- 43 | 44 | # application home page (will override Website Settings) 45 | # home_page = "login" 46 | 47 | # website user home page (by Role) 48 | # role_home_page = { 49 | # "Role": "home_page" 50 | # } 51 | 52 | # Website user home page (by function) 53 | # get_website_user_home_page = "whatsapp_integration.utils.get_home_page" 54 | 55 | # Generators 56 | # ---------- 57 | 58 | # automatically create page for each record of this doctype 59 | # website_generators = ["Web Page"] 60 | 61 | # Installation 62 | # ------------ 63 | 64 | # before_install = "whatsapp_integration.install.before_install" 65 | # after_install = "whatsapp_integration.install.after_install" 66 | 67 | # Desk Notifications 68 | # ------------------ 69 | # See frappe.core.notifications.get_notification_config 70 | 71 | # notification_config = "whatsapp_integration.notifications.get_notification_config" 72 | 73 | # Permissions 74 | # ----------- 75 | # Permissions evaluated in scripted ways 76 | 77 | # permission_query_conditions = { 78 | # "Event": "frappe.desk.doctype.event.event.get_permission_query_conditions", 79 | # } 80 | # 81 | # has_permission = { 82 | # "Event": "frappe.desk.doctype.event.event.has_permission", 83 | # } 84 | 85 | # Document Events 86 | # --------------- 87 | # Hook on document methods and events 88 | 89 | # doc_events = { 90 | # "*": { 91 | # "on_update": "method", 92 | # "on_cancel": "method", 93 | # "on_trash": "method" 94 | # } 95 | # } 96 | 97 | # Scheduled Tasks 98 | # --------------- 99 | 100 | # scheduler_events = { 101 | # "all": [ 102 | # "whatsapp_integration.tasks.all" 103 | # ], 104 | # "daily": [ 105 | # "whatsapp_integration.tasks.daily" 106 | # ], 107 | # "hourly": [ 108 | # "whatsapp_integration.tasks.hourly" 109 | # ], 110 | # "weekly": [ 111 | # "whatsapp_integration.tasks.weekly" 112 | # ] 113 | # "monthly": [ 114 | # "whatsapp_integration.tasks.monthly" 115 | # ] 116 | # } 117 | 118 | # Testing 119 | # ------- 120 | 121 | # before_tests = "whatsapp_integration.install.before_tests" 122 | 123 | # Overriding Methods 124 | # ------------------------------ 125 | # 126 | # override_whitelisted_methods = { 127 | # "frappe.desk.doctype.event.event.get_events": "whatsapp_integration.event.get_events" 128 | # } 129 | # 130 | # each overriding function accepts a `data` argument; 131 | # generated from the base implementation of the doctype dashboard, 132 | # along with any modifications made in other Frappe apps 133 | # override_doctype_dashboards = { 134 | # "Task": "whatsapp_integration.task.get_dashboard_data" 135 | # } 136 | 137 | -------------------------------------------------------------------------------- /whatsapp_integration/modules.txt: -------------------------------------------------------------------------------- 1 | Whatsapp Integration -------------------------------------------------------------------------------- /whatsapp_integration/patches.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netmanthan/erpnext_whatsapp/1b6c7957c6340833742b67365c2627e57fd3646f/whatsapp_integration/patches.txt -------------------------------------------------------------------------------- /whatsapp_integration/public/js/moneky_whatsapp.js: -------------------------------------------------------------------------------- 1 | 2 | if(!erpnext.common_SMSManager){ 3 | erpnext.common_SMSManager = erpnext.SMSManager; 4 | } 5 | 6 | 7 | erpnext.SMSManager = function(doc) { 8 | var me = this; 9 | this.setup = function() { 10 | var default_msg = { 11 | 'Lead' : '', 12 | 'Opportunity' : 'Your enquiry has been logged into the system. Ref No: ' + doc.name, 13 | 'Quotation' : 'Quotation ' + doc.name + ' has been sent via email. Thanks!', 14 | 'Sales Order' : 'Sales Order ' + doc.name + ' has been created against ' 15 | + (doc.quotation_no ? ('Quote No:' + doc.quotation_no) : '') 16 | + (doc.po_no ? (' for your PO: ' + doc.po_no) : ''), 17 | 'Delivery Note' : 'Items has been delivered against delivery note: ' + doc.name 18 | + (doc.po_no ? (' for your PO: ' + doc.po_no) : ''), 19 | 'Sales Invoice': 'Invoice ' + doc.name + ' has been sent via email ' 20 | + (doc.po_no ? (' for your PO: ' + doc.po_no) : ''), 21 | 'Material Request' : 'Material Request ' + doc.name + ' has been raised in the system', 22 | 'Purchase Order' : 'Purchase Order ' + doc.name + ' has been sent via email', 23 | 'Purchase Receipt' : 'Items has been received against purchase receipt: ' + doc.name 24 | } 25 | 26 | if (in_list(['Sales Order', 'Delivery Note', 'Sales Invoice'], doc.doctype)) 27 | this.show(doc.contact_person, 'Customer', doc.customer, '', default_msg[doc.doctype]); 28 | else if (doc.doctype === 'Quotation') 29 | this.show(doc.contact_person, 'Customer', doc.party_name, '', default_msg[doc.doctype]); 30 | else if (in_list(['Purchase Order', 'Purchase Receipt'], doc.doctype)) 31 | this.show(doc.contact_person, 'Supplier', doc.supplier, '', default_msg[doc.doctype]); 32 | else if (doc.doctype == 'Lead') 33 | this.show('', '', '', doc.mobile_no, default_msg[doc.doctype]); 34 | else if (doc.doctype == 'Opportunity') 35 | this.show('', '', '', doc.contact_no, default_msg[doc.doctype]); 36 | else if (doc.doctype == 'Material Request') 37 | this.show('', '', '', '', default_msg[doc.doctype]); 38 | }; 39 | 40 | this.get_contact_number = function(contact, ref_doctype, ref_name) { 41 | frappe.call({ 42 | method: "frappe.core.doctype.sms_settings.sms_settings.get_contact_number", 43 | args: { 44 | contact_name: contact, 45 | ref_doctype: ref_doctype, 46 | ref_name: ref_name 47 | }, 48 | callback: function(r) { 49 | if(r.exc) { frappe.msgprint(r.exc); return; } 50 | me.number = r.message; 51 | me.show_dialog(); 52 | } 53 | }); 54 | }; 55 | 56 | this.show = function(contact, ref_doctype, ref_name, mobile_nos, message) { 57 | this.message = message; 58 | if (mobile_nos) { 59 | me.number = mobile_nos; 60 | me.show_dialog(); 61 | } else if (contact){ 62 | this.get_contact_number(contact, ref_doctype, ref_name) 63 | } else { 64 | me.show_dialog(); 65 | } 66 | } 67 | this.show_dialog = function() { 68 | if(!me.dialog) 69 | me.make_dialog(); 70 | me.dialog.set_values({ 71 | 'message': me.message, 72 | 'number': me.number 73 | }) 74 | me.dialog.show(); 75 | } 76 | this.make_dialog = function() { 77 | var d = new frappe.ui.Dialog({ 78 | title: 'Send Message', 79 | width: 400, 80 | fields: [ 81 | { 82 | fieldname:'type', 83 | fieldtype:'Select', 84 | label:'Message Type', 85 | reqd:1, 86 | options:"SMS\nWhatsapp", 87 | default:"SMS", 88 | onchange: function(){ 89 | var field = this.layout.get_field("send_attachment"); 90 | if(this.layout.fields_dict.type.value == "Whatsapp"){ 91 | field.df.hidden = false; 92 | } 93 | else{ 94 | field.df.hidden = true; 95 | } 96 | field.refresh(); 97 | } 98 | }, 99 | {fieldname:'number', fieldtype:'Data', label:'Mobile Number', reqd:1}, 100 | {fieldname:'message', fieldtype:'Text', label:'Message', reqd:1}, 101 | {fieldname:'send', fieldtype:'Button', label:'Send'}, 102 | {fieldname:'send_attachment', fieldtype:'Check', label:'Attach Document Print', hidden: true} 103 | ] 104 | }) 105 | d.fields_dict.send.input.onclick = function() { 106 | var btn = d.fields_dict.send.input; 107 | var v = me.dialog.get_values(); 108 | if(v) { 109 | $(btn).set_working(); 110 | var correct_method = "frappe.core.doctype.sms_settings.sms_settings.send_sms"; 111 | 112 | var args_dict = { 113 | receiver_list: [v.number], 114 | msg: v.message 115 | } 116 | 117 | if(d.fields_dict.type.value == "Whatsapp"){ 118 | correct_method = "whatsapp_integration.api.send_whatsapp"; 119 | var has_attachment = d.fields_dict.send_attachment.get_value(); 120 | args_dict["doctype"] = (has_attachment == 1? doc.doctype:""); 121 | args_dict["name"] = (has_attachment == 1? doc.name:""); 122 | } 123 | frappe.call({ 124 | method: correct_method, 125 | args: args_dict, 126 | callback: function(r) { 127 | $(btn).done_working(); 128 | if(r.exc) {frappe.msgprint(r.exc); return; } 129 | me.dialog.hide(); 130 | } 131 | }); 132 | } 133 | } 134 | this.dialog = d; 135 | } 136 | this.setup(); 137 | } -------------------------------------------------------------------------------- /whatsapp_integration/public/js/sms_center.js: -------------------------------------------------------------------------------- 1 | frappe.ui.form.on("SMS Center", "send_whatsapp", function(frm) { 2 | 3 | frappe.call({ 4 | method: "whatsapp_integration.api.send_whatsapp", 5 | args: { 6 | receiver_list: frm.doc.receiver_list, 7 | doctype: 'SMS Center', 8 | msg: frm.doc.message 9 | }, 10 | callback: function(r, rt) { 11 | if (r.message) { 12 | frappe.msgprint(r.message); 13 | } 14 | } 15 | }); 16 | }); -------------------------------------------------------------------------------- /whatsapp_integration/templates/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netmanthan/erpnext_whatsapp/1b6c7957c6340833742b67365c2627e57fd3646f/whatsapp_integration/templates/__init__.py -------------------------------------------------------------------------------- /whatsapp_integration/templates/pages/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netmanthan/erpnext_whatsapp/1b6c7957c6340833742b67365c2627e57fd3646f/whatsapp_integration/templates/pages/__init__.py -------------------------------------------------------------------------------- /whatsapp_integration/whatsapp_integration/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netmanthan/erpnext_whatsapp/1b6c7957c6340833742b67365c2627e57fd3646f/whatsapp_integration/whatsapp_integration/__init__.py -------------------------------------------------------------------------------- /whatsapp_integration/whatsapp_integration/doctype/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netmanthan/erpnext_whatsapp/1b6c7957c6340833742b67365c2627e57fd3646f/whatsapp_integration/whatsapp_integration/doctype/__init__.py -------------------------------------------------------------------------------- /whatsapp_integration/whatsapp_integration/doctype/whatsapp_settings/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netmanthan/erpnext_whatsapp/1b6c7957c6340833742b67365c2627e57fd3646f/whatsapp_integration/whatsapp_integration/doctype/whatsapp_settings/__init__.py -------------------------------------------------------------------------------- /whatsapp_integration/whatsapp_integration/doctype/whatsapp_settings/test_whatsapp_settings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors 3 | # See license.txt 4 | from __future__ import unicode_literals 5 | 6 | # import frappe 7 | import unittest 8 | 9 | class TestWhatsappSettings(unittest.TestCase): 10 | pass 11 | -------------------------------------------------------------------------------- /whatsapp_integration/whatsapp_integration/doctype/whatsapp_settings/whatsapp_settings.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Whatsapp Settings', { 5 | // refresh: function(frm) { 6 | 7 | // } 8 | }); 9 | -------------------------------------------------------------------------------- /whatsapp_integration/whatsapp_integration/doctype/whatsapp_settings/whatsapp_settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "creation": "2019-10-03 10:15:49.624148", 3 | "doctype": "DocType", 4 | "editable_grid": 1, 5 | "engine": "InnoDB", 6 | "field_order": [ 7 | "wp_number", 8 | "section_break_3", 9 | "twilio_sid", 10 | "twilio_token" 11 | ], 12 | "fields": [ 13 | { 14 | "fieldname": "twilio_sid", 15 | "fieldtype": "Data", 16 | "label": "Account SID" 17 | }, 18 | { 19 | "fieldname": "twilio_token", 20 | "fieldtype": "Data", 21 | "label": "Auth Token" 22 | }, 23 | { 24 | "fieldname": "wp_number", 25 | "fieldtype": "Data", 26 | "label": "Phone Number" 27 | }, 28 | { 29 | "fieldname": "section_break_3", 30 | "fieldtype": "Section Break" 31 | } 32 | ], 33 | "issingle": 1, 34 | "modified": "2019-10-03 11:43:24.159010", 35 | "modified_by": "Administrator", 36 | "module": "Whatsapp Integration", 37 | "name": "Whatsapp Settings", 38 | "owner": "Administrator", 39 | "permissions": [ 40 | { 41 | "create": 1, 42 | "delete": 1, 43 | "email": 1, 44 | "print": 1, 45 | "read": 1, 46 | "role": "System Manager", 47 | "share": 1, 48 | "write": 1 49 | } 50 | ], 51 | "quick_entry": 1, 52 | "sort_field": "modified", 53 | "sort_order": "DESC", 54 | "track_changes": 1 55 | } -------------------------------------------------------------------------------- /whatsapp_integration/whatsapp_integration/doctype/whatsapp_settings/whatsapp_settings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors 3 | # For license information, please see license.txt 4 | 5 | from __future__ import unicode_literals 6 | from frappe.model.document import Document 7 | from frappe.core.doctype.sms_settings.sms_settings import validate_receiver_nos 8 | 9 | 10 | class WhatsappSettings(Document): 11 | def validate(self): 12 | validate_receiver_nos([self.wp_number]) 13 | --------------------------------------------------------------------------------