├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── MANIFEST.in ├── README.md ├── batch.PNG ├── license.txt ├── package.json ├── posawesome ├── __init__.py ├── config │ ├── __init__.py │ ├── desktop.py │ ├── docs.py │ └── pos_awesome.py ├── fixtures │ ├── custom_field.json │ └── property_setter.json ├── hooks.py ├── modules.txt ├── patches.txt ├── posawesome │ ├── __init__.py │ ├── api │ │ ├── __init__.py │ │ ├── company.js │ │ ├── customer.py │ │ ├── invoice.js │ │ ├── invoice.py │ │ ├── m_pesa.py │ │ ├── payment_entry.py │ │ ├── pos_profile.js │ │ ├── posapp.py │ │ ├── status_updater.py │ │ └── taxes.py │ ├── doctype │ │ ├── __init__.py │ │ ├── delivery_charges │ │ │ ├── __init__.py │ │ │ ├── delivery_charges.js │ │ │ ├── delivery_charges.json │ │ │ ├── delivery_charges.py │ │ │ └── test_delivery_charges.py │ │ ├── delivery_charges_pos_profile │ │ │ ├── __init__.py │ │ │ ├── delivery_charges_pos_profile.json │ │ │ └── delivery_charges_pos_profile.py │ │ ├── mpesa_c2b_register_url │ │ │ ├── __init__.py │ │ │ ├── mpesa_c2b_register_url.js │ │ │ ├── mpesa_c2b_register_url.json │ │ │ ├── mpesa_c2b_register_url.py │ │ │ └── test_mpesa_c2b_register_url.py │ │ ├── mpesa_payment_register │ │ │ ├── __init__.py │ │ │ ├── mpesa_payment_register.js │ │ │ ├── mpesa_payment_register.json │ │ │ ├── mpesa_payment_register.py │ │ │ └── test_mpesa_payment_register.py │ │ ├── pos_closing_shift │ │ │ ├── __init__.py │ │ │ ├── closing_shift_details.html │ │ │ ├── pos_closing_shift.js │ │ │ ├── pos_closing_shift.json │ │ │ ├── pos_closing_shift.py │ │ │ └── test_pos_closing_shift.py │ │ ├── pos_closing_shift_detail │ │ │ ├── __init__.py │ │ │ ├── pos_closing_shift_detail.json │ │ │ └── pos_closing_shift_detail.py │ │ ├── pos_closing_shift_taxes │ │ │ ├── __init__.py │ │ │ ├── pos_closing_shift_taxes.json │ │ │ └── pos_closing_shift_taxes.py │ │ ├── pos_coupon │ │ │ ├── __init__.py │ │ │ ├── pos_coupon.js │ │ │ ├── pos_coupon.json │ │ │ ├── pos_coupon.py │ │ │ └── test_pos_coupon.py │ │ ├── pos_coupon_detail │ │ │ ├── __init__.py │ │ │ ├── pos_coupon_detail.json │ │ │ └── pos_coupon_detail.py │ │ ├── pos_offer │ │ │ ├── __init__.py │ │ │ ├── pos_offer.js │ │ │ ├── pos_offer.json │ │ │ ├── pos_offer.py │ │ │ └── test_pos_offer.py │ │ ├── pos_offer_detail │ │ │ ├── __init__.py │ │ │ ├── pos_offer_detail.json │ │ │ └── pos_offer_detail.py │ │ ├── pos_opening_shift │ │ │ ├── __init__.py │ │ │ ├── pos_opening_shift.js │ │ │ ├── pos_opening_shift.json │ │ │ ├── pos_opening_shift.py │ │ │ ├── pos_opening_shift_list.js │ │ │ └── test_pos_opening_shift.py │ │ ├── pos_opening_shift_detail │ │ │ ├── __init__.py │ │ │ ├── pos_opening_shift_detail.json │ │ │ └── pos_opening_shift_detail.py │ │ ├── pos_payment_entry_reference │ │ │ ├── __init__.py │ │ │ ├── pos_payment_entry_reference.json │ │ │ └── pos_payment_entry_reference.py │ │ ├── referral_code │ │ │ ├── __init__.py │ │ │ ├── referral_code.js │ │ │ ├── referral_code.json │ │ │ ├── referral_code.py │ │ │ └── test_referral_code.py │ │ └── sales_invoice_reference │ │ │ ├── __init__.py │ │ │ ├── sales_invoice_reference.json │ │ │ └── sales_invoice_reference.py │ ├── page │ │ ├── __init__.py │ │ └── posapp │ │ │ ├── __init__.py │ │ │ ├── onscan.js │ │ │ ├── posapp.js │ │ │ └── posapp.json │ └── workspace │ │ └── pos_awesome │ │ └── pos_awesome.json ├── public │ └── js │ │ ├── posapp │ │ ├── Home.vue │ │ ├── bus.js │ │ ├── components │ │ │ ├── Navbar.vue │ │ │ ├── payments │ │ │ │ └── Pay.vue │ │ │ └── pos │ │ │ │ ├── ClosingDialog.vue │ │ │ │ ├── Customer.vue │ │ │ │ ├── Drafts.vue │ │ │ │ ├── Invoice.vue │ │ │ │ ├── ItemsSelector.vue │ │ │ │ ├── Mpesa-Payments.vue │ │ │ │ ├── NewAddress.vue │ │ │ │ ├── OpeningDialog.vue │ │ │ │ ├── Payments.vue │ │ │ │ ├── Pos.vue │ │ │ │ ├── PosCoupons.vue │ │ │ │ ├── PosOffers.vue │ │ │ │ ├── Returns.vue │ │ │ │ ├── SalesOrders.vue │ │ │ │ ├── UpdateCustomer.vue │ │ │ │ ├── Variants.vue │ │ │ │ ├── placeholder-image.png │ │ │ │ └── pos.png │ │ ├── format.js │ │ └── posapp.js │ │ ├── posawesome.bundle.js │ │ └── toConsole.js ├── templates │ ├── __init__.py │ └── pages │ │ ├── __init__.py │ │ └── __pycache__ │ │ └── __init__.py ├── translations │ └── pt.csv └── uninstall.py ├── requirements.txt ├── setup.py ├── wiki_images ├── CONFIG AND FILTERS.PNG ├── CONFIGIRATION.PNG ├── Customer icon.PNG ├── PAYMENT METHODS.PNG ├── PROMOS.PNG ├── QUANTITYCONDITIONS.PNG ├── auto set.PNG ├── batch price.PNG ├── batch pricing show.PNG ├── batch.PNG ├── cake.PNG ├── cakes 2.PNG ├── changeview.PNG ├── closing popup.PNG ├── credit sale.PNG ├── cust4loyalty.PNG ├── customer credit.PNG ├── customer search.PNG ├── delivery 2.PNG ├── delivery date.PNG ├── endofshift.PNG ├── hiddenshift.PNG ├── hide shift.PNG ├── inside pos offers.PNG ├── item details.PNG ├── label.PNG ├── listview.PNG ├── loyalty view.PNG ├── new advanced awesome settings.PNG ├── opening.png ├── options2.png ├── payment cart.PNG ├── payment.PNG ├── popup.PNG ├── pos 1.PNG ├── pos closing 3.PNG ├── posclosing1.PNG ├── posclosing2.PNG ├── profile1.PNG ├── profile2.PNG ├── promo type.png ├── qualifying section.PNG ├── qualigying options.png ├── readme.md ├── redeem.PNG ├── replace.PNG ├── return button.PNG ├── return cart.PNG ├── return search.PNG ├── rewatrd.PNG ├── sales order.PNG ├── scale.PNG ├── search.PNG ├── serial numbers.PNG ├── shiftdiff.PNG ├── starting.PNG └── users.PNG └── yarn.lock /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]: " 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 20 | - Erpnext: 21 | - POS Awesome: 22 | 23 | ### Stacktrace / full error message 24 | 25 | ```javascript 26 | (paste here) 27 | ``` 28 | 29 | ### Steps to reproduce 30 | 31 | 1. Go to '...' 32 | 2. Click on '....' 33 | 3. Scroll down to '....' 34 | 4. See the error 35 | 36 | ### What is Expected? 37 | 38 | 39 | ### What is actually happening? 40 | 41 | 42 | ### Additional context 43 | Add any other context about the problem here. 44 | 45 | 46 | ### Screenshots 47 | If applicable, could you add screenshots to help explain your problem? 48 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[Feature request]: " 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | ### Is your feature request related to a problem? Please describe. 13 | 14 | 15 | 16 | 17 | ### Describe the solution you'd like 18 | 19 | 20 | 21 | 22 | ### Describe alternatives you've considered 23 | 24 | 25 | 26 | 27 | ### Additional context 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pyc 3 | *.egg-info 4 | *.swp 5 | tags 6 | posawesome/docs/current 7 | node_modules 8 | posawesome/public/dist -------------------------------------------------------------------------------- /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 posawesome *.css 8 | recursive-include posawesome *.csv 9 | recursive-include posawesome *.html 10 | recursive-include posawesome *.ico 11 | recursive-include posawesome *.js 12 | recursive-include posawesome *.json 13 | recursive-include posawesome *.md 14 | recursive-include posawesome *.png 15 | recursive-include posawesome *.py 16 | recursive-include posawesome *.svg 17 | recursive-include posawesome *.txt 18 | recursive-exclude posawesome *.pyc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |

POS AWESOME

4 |
5 | 6 | #### An open-source Point of Sale for [Erpnext](https://github.com/frappe/erpnext) using [Vue.js](https://github.com/vuejs/vue) and [Vuetify](https://github.com/vuetifyjs/vuetify) 7 | 8 | --- 9 | 10 | ### Main Features 11 | 12 | 1. Supports Erpnext Version 14 13 | 2. User friendly and provides a good user experience and speed of use 14 | 3. The cashier has the option of either using list view or card view during sales transactions. Card view shows the images of the items 15 | 4. Supports enqueue invoice submission after printing the receipt for faster processing 16 | 5. Supports batch & serial numbering 17 | 6. Supports batch based pricing 18 | 7. Supports UOM specific barcode and pricing 19 | 8. Supports sales of scale (weighted) products 20 | 9. Ability to make returns from POS 21 | 10. Supports Making returns for either cash or customer credit 22 | 11. Supports using customer credit note for payment 23 | 12. Supports credit sales 24 | 13. Allows user to choose a due date for credit sales 25 | 14. Supports customer loyalty points 26 | 15. Shortcuts keys 27 | 16. Supports Customer Discount 28 | 17. Supports POS Offers 29 | 18. Auto apply batches for bundle items 30 | 19. Search and add items by Serial Number 31 | 20. Create Sales Order from POS directly 32 | 21. Supports template items with variants 33 | 22. Supports multiple languages 34 | 23. Supports Mpesa mobile payment 35 | 24. POS Coupons 36 | 25. Supports Referral Code 37 | 26. Supports Customer and Customer Group price list 38 | 27. Supports Sales Person 39 | 28. Supports Delivery Charges 40 | 29. Search and add items by Batch Number 41 | 30. Accept new payments from customers against existing invoices 42 | 31. Payments Reconciliation 43 | 44 | --- 45 | 46 | ### How to Install 47 | 48 | #### Frappe Cloud: 49 | 50 | One-click installing available if you are hosting on FC from [here](https://frappecloud.com/marketplace/apps/posawesome) 51 | 52 | #### Self Hosting: 53 | 54 | 1. `bench get-app branch version-14 https://github.com/yrestom/POS-Awesome.git` 55 | 2. `bench setup requirements` 56 | 3. `bench build --app posawesome` 57 | 4. `bench restart` 58 | 5. `bench --site [your.site.name] install-app posawesome` 59 | 6. `bench --site [your.site.name] migrate` 60 | 61 | --- 62 | 63 | ### Support 64 | 65 | #### Frappe Cloud: 66 | 67 | If you are hosting on FC premium support is available [here](https://frappecloud.com/marketplace/apps/posawesome) 68 | 69 | #### Self Hosting: 70 | 71 | If you need premium support please email me [here](mailto:info@totrox.com) 72 | 73 | #### Community Support: 74 | 75 | Available in GitHub [discussions](https://github.com/yrestom/POS-Awesome/discussions) 76 | 77 | --- 78 | 79 | ### New Features and Bug report: 80 | 81 | - Please Create Github Issue from [here](https://github.com/yrestom/POS-Awesome/issues/new/choose) after checking the existing issues 82 | - For paid features, you can email me [here](mailto:info@totrox.com) 83 | 84 | --- 85 | 86 | ### How To Use: 87 | 88 | [POS Awesome Wiki](https://github.com/yrestom/POS-Awesome/wiki) 89 | 90 | --- 91 | 92 | ### Shortcuts: 93 | 94 | - `CTRL or CMD + S` open payments 95 | - `CTRL or CMD + X` submit payments 96 | - `CTRL or CMD + D` remove first item from the top 97 | - `CTRL or CMD + A` expand first item from the top 98 | - `CTRL or CMD + E` focus on discount field 99 | 100 | --- 101 | 102 | ### Dependencies: 103 | 104 | - [Frappe](https://github.com/frappe/frappe) 105 | - [Erpnext](https://github.com/frappe/erpnext) 106 | - [Vue.js](https://github.com/vuejs/vue) 107 | - [Vuetify.js](https://github.com/vuetifyjs/vuetify) 108 | 109 | --- 110 | 111 | ### Contributing 112 | 113 | Will using for this the same guidelines from Erpnext 114 | 115 | 1. [Issue Guidelines](https://github.com/frappe/erpnext/wiki/Issue-Guidelines) 116 | 2. [Pull Request Requirements](https://github.com/frappe/erpnext/wiki/Contribution-Guidelines) 117 | 118 | --- 119 | 120 | ### License 121 | 122 | GNU/General Public License (see [license.txt](https://github.com/yrestom/POS-Awesome/blob/master/license.txt)) 123 | 124 | The POS Awesome code is licensed as GNU General Public License (v3) 125 | -------------------------------------------------------------------------------- /batch.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/batch.PNG -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "lodash": "^4.17.21", 4 | "vuetify": "^2.6.10" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /posawesome/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | import frappe 4 | 5 | __version__ = "6.3.0" 6 | 7 | 8 | def console(*data): 9 | frappe.publish_realtime("toconsole", data, user=frappe.session.user) 10 | -------------------------------------------------------------------------------- /posawesome/config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/config/__init__.py -------------------------------------------------------------------------------- /posawesome/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": "POS Awesome", 9 | "category": "Modules", 10 | "color": "grey", 11 | "icon": "octicon octicon-file-directory", 12 | "type": "module", 13 | "label": _("POS Awesome") 14 | } 15 | ] 16 | -------------------------------------------------------------------------------- /posawesome/config/docs.py: -------------------------------------------------------------------------------- 1 | """ 2 | Configuration for docs 3 | """ 4 | 5 | # source_link = "https://github.com/[org_name]/posawesome" 6 | # docs_base_url = "https://[org_name].github.io/posawesome" 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 = "POS Awesome" 12 | -------------------------------------------------------------------------------- /posawesome/config/pos_awesome.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | from frappe import _ 3 | 4 | def get_data(): 5 | return [ 6 | { 7 | "label": _("POS Awesome"), 8 | "items": [ 9 | { 10 | "description": "POS Awesome", 11 | "name": "posapp", 12 | "label": "POSAPP", 13 | "type": "page" 14 | }, 15 | 16 | { 17 | "type": "doctype", 18 | "description": "POS Profile", 19 | "name": "POS Profile", 20 | }, 21 | 22 | { 23 | "type": "doctype", 24 | "description": "POS Opening Shift", 25 | "name": "POS Opening Shift", 26 | }, 27 | { 28 | "type": "doctype", 29 | "description": "POS Closing Shift", 30 | "name": "POS Closing Shift", 31 | }, 32 | { 33 | "type": "doctype", 34 | "description": "POS Offers", 35 | "name": "POS Offer", 36 | }, 37 | ] 38 | 39 | } 40 | ] 41 | -------------------------------------------------------------------------------- /posawesome/fixtures/property_setter.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "default_value": null, 4 | "doc_type": "Sales Invoice", 5 | "docstatus": 0, 6 | "doctype": "Property Setter", 7 | "doctype_or_field": "DocField", 8 | "field_name": "posa_pos_opening_shift", 9 | "is_system_generated": 0, 10 | "modified": "2020-10-26 15:35:40.861492", 11 | "module": null, 12 | "name": "Sales Invoice-posa_pos_opening_shift-no_copy", 13 | "property": "no_copy", 14 | "property_type": "Check", 15 | "row_name": null, 16 | "value": "1" 17 | } 18 | ] -------------------------------------------------------------------------------- /posawesome/modules.txt: -------------------------------------------------------------------------------- 1 | POSAwesome -------------------------------------------------------------------------------- /posawesome/patches.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/patches.txt -------------------------------------------------------------------------------- /posawesome/posawesome/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/posawesome/__init__.py -------------------------------------------------------------------------------- /posawesome/posawesome/api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/posawesome/api/__init__.py -------------------------------------------------------------------------------- /posawesome/posawesome/api/company.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021, Youssef Restom and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Company', { 5 | setup: function (frm) { 6 | frm.set_query("posa_customer_offer", function () { 7 | return { 8 | filters: { 9 | "company": frm.doc.name, 10 | "coupon_based": 1, 11 | "disable": 0, 12 | } 13 | }; 14 | }); 15 | frm.set_query("posa_primary_offer", function () { 16 | return { 17 | filters: { 18 | "company": frm.doc.name, 19 | "coupon_based": 1, 20 | "disable": 0, 21 | } 22 | }; 23 | }); 24 | }, 25 | }); -------------------------------------------------------------------------------- /posawesome/posawesome/api/customer.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Youssef Restom and contributors 2 | # For license information, please see license.txt 3 | 4 | from __future__ import unicode_literals 5 | import frappe 6 | from frappe import _ 7 | from posawesome.posawesome.doctype.referral_code.referral_code import ( 8 | create_referral_code, 9 | ) 10 | 11 | 12 | def after_insert(doc, method): 13 | create_customer_referral_code(doc) 14 | create_gift_coupon(doc) 15 | 16 | 17 | def validate(doc, method): 18 | validate_referral_code(doc) 19 | 20 | 21 | def create_customer_referral_code(doc): 22 | if doc.posa_referral_company: 23 | company = frappe.get_cached_doc("Company", doc.posa_referral_company) 24 | if not company.posa_auto_referral: 25 | return 26 | create_referral_code( 27 | doc.posa_referral_company, 28 | doc.name, 29 | company.posa_customer_offer, 30 | company.posa_primary_offer, 31 | company.posa_referral_campaign, 32 | ) 33 | 34 | 35 | def create_gift_coupon(doc): 36 | if doc.posa_referral_code: 37 | coupon = frappe.new_doc("POS Coupon") 38 | coupon.customer = doc.name 39 | coupon.referral_code = doc.posa_referral_code 40 | coupon.create_coupon_from_referral() 41 | 42 | 43 | def validate_referral_code(doc): 44 | referral_code = doc.posa_referral_code 45 | exist = None 46 | if referral_code: 47 | exist = frappe.db.exists("Referral Code", referral_code) 48 | if not exist: 49 | exist = frappe.db.exists("Referral Code", {"referral_code": referral_code}) 50 | if not exist: 51 | frappe.throw(_("This Referral Code {0} not exists").format(referral_code)) 52 | -------------------------------------------------------------------------------- /posawesome/posawesome/api/invoice.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 20201 Youssef Restom and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Sales Invoice', { 5 | setup: function (frm) { 6 | frm.set_query("posa_delivery_charges", function (doc) { 7 | return { 8 | filters: { 'company': doc.company, 'disabled': 0 } 9 | }; 10 | }); 11 | }, 12 | }); -------------------------------------------------------------------------------- /posawesome/posawesome/api/m_pesa.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Youssef Restom and contributors 2 | # For license information, please see license.txt 3 | 4 | from __future__ import unicode_literals 5 | import frappe, requests 6 | from frappe import _ 7 | from requests.auth import HTTPBasicAuth 8 | import json 9 | 10 | 11 | def get_token(app_key, app_secret, base_url): 12 | authenticate_uri = "/oauth/v1/generate?grant_type=client_credentials" 13 | authenticate_url = "{0}{1}".format(base_url, authenticate_uri) 14 | 15 | r = requests.get(authenticate_url, auth=HTTPBasicAuth(app_key, app_secret)) 16 | 17 | return r.json()["access_token"] 18 | 19 | 20 | @frappe.whitelist(allow_guest=True) 21 | def confirmation(**kwargs): 22 | try: 23 | args = frappe._dict(kwargs) 24 | doc = frappe.new_doc("Mpesa Payment Register") 25 | doc.transactiontype = args.get("TransactionType") 26 | doc.transid = args.get("TransID") 27 | doc.transtime = args.get("TransTime") 28 | doc.transamount = args.get("TransAmount") 29 | doc.businessshortcode = args.get("BusinessShortCode") 30 | doc.billrefnumber = args.get("BillRefNumber") 31 | doc.invoicenumber = args.get("InvoiceNumber") 32 | doc.orgaccountbalance = args.get("OrgAccountBalance") 33 | doc.thirdpartytransid = args.get("ThirdPartyTransID") 34 | doc.msisdn = args.get("MSISDN") 35 | doc.firstname = args.get("FirstName") 36 | doc.middlename = args.get("MiddleName") 37 | doc.lastname = args.get("LastName") 38 | doc.insert(ignore_permissions=True) 39 | frappe.db.commit() 40 | context = {"ResultCode": 0, "ResultDesc": "Accepted"} 41 | return dict(context) 42 | except Exception as e: 43 | frappe.log_error(frappe.get_traceback(), str(e)[:140]) 44 | context = {"ResultCode": 1, "ResultDesc": "Rejected"} 45 | return dict(context) 46 | 47 | 48 | @frappe.whitelist(allow_guest=True) 49 | def validation(**kwargs): 50 | context = {"ResultCode": 0, "ResultDesc": "Accepted"} 51 | return dict(context) 52 | 53 | 54 | @frappe.whitelist() 55 | def get_mpesa_mode_of_payment(company): 56 | modes = frappe.get_all( 57 | "Mpesa C2B Register URL", 58 | filters={"company": company, "register_status": "Success"}, 59 | fields=["mode_of_payment"], 60 | ) 61 | modes_of_payment = [] 62 | for mode in modes: 63 | if mode.mode_of_payment not in modes_of_payment: 64 | modes_of_payment.append(mode.mode_of_payment) 65 | return modes_of_payment 66 | 67 | 68 | @frappe.whitelist() 69 | def get_mpesa_draft_payments( 70 | company, 71 | mode_of_payment=None, 72 | mobile_no=None, 73 | full_name=None, 74 | payment_methods_list=None, 75 | ): 76 | filters = {"company": company, "docstatus": 0} 77 | if mode_of_payment: 78 | filters["mode_of_payment"] = mode_of_payment 79 | if mobile_no: 80 | filters["msisdn"] = ["like", f"%{mobile_no}%"] 81 | if full_name: 82 | filters["full_name"] = ["like", f"%{full_name}%"] 83 | if payment_methods_list: 84 | filters["mode_of_payment"] = ["in", json.loads(payment_methods_list)] 85 | 86 | payments = frappe.get_all( 87 | "Mpesa Payment Register", 88 | filters=filters, 89 | fields=[ 90 | "name", 91 | "transid", 92 | "msisdn as mobile_no", 93 | "full_name", 94 | "posting_date", 95 | "transamount as amount", 96 | "currency", 97 | "mode_of_payment", 98 | "company", 99 | ], 100 | order_by="posting_date desc", 101 | ) 102 | return payments 103 | 104 | 105 | @frappe.whitelist() 106 | def submit_mpesa_payment(mpesa_payment, customer): 107 | doc = frappe.get_doc("Mpesa Payment Register", mpesa_payment) 108 | doc.customer = customer 109 | doc.submit_payment = 1 110 | doc.submit() 111 | doc.reload() 112 | return frappe.get_doc("Payment Entry", doc.payment_entry) 113 | -------------------------------------------------------------------------------- /posawesome/posawesome/api/pos_profile.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 20201 Youssef Restom and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('POS Profile', { 5 | setup: function (frm) { 6 | frm.set_query("posa_cash_mode_of_payment", function (doc) { 7 | return { 8 | filters: { 'type': 'Cash' } 9 | }; 10 | }); 11 | }, 12 | }); -------------------------------------------------------------------------------- /posawesome/posawesome/api/status_updater.py: -------------------------------------------------------------------------------- 1 | ## -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Youssef Restom and contributors 3 | # For license information, please see license.txt 4 | 5 | from __future__ import unicode_literals 6 | import frappe 7 | from frappe.utils import comma_or, nowdate, getdate 8 | from frappe import _ 9 | from frappe.model.document import Document 10 | 11 | class OverAllowanceError(frappe.ValidationError): pass 12 | 13 | def validate_status(status, options): 14 | if status not in options: 15 | frappe.throw(_("Status must be one of {0}").format(comma_or(options))) 16 | 17 | status_map = { 18 | "POS Opening Shift": [ 19 | ["Draft", None], 20 | ["Open", "eval:self.docstatus == 1 and not self.pos_closing_shift"], 21 | ["Closed", "eval:self.docstatus == 1 and self.pos_closing_shift"], 22 | ["Cancelled", "eval:self.docstatus == 2"], 23 | ] 24 | } 25 | 26 | class StatusUpdater(Document): 27 | 28 | def set_status(self, update=False, status=None, update_modified=True): 29 | if self.is_new(): 30 | if self.get('amended_from'): 31 | self.status = 'Draft' 32 | return 33 | 34 | if self.doctype in status_map: 35 | _status = self.status 36 | if status and update: 37 | self.db_set("status", status) 38 | 39 | sl = status_map[self.doctype][:] 40 | sl.reverse() 41 | for s in sl: 42 | if not s[1]: 43 | self.status = s[0] 44 | break 45 | elif s[1].startswith("eval:"): 46 | if frappe.safe_eval(s[1][5:], None, { "self": self.as_dict(), "getdate": getdate, 47 | "nowdate": nowdate, "get_value": frappe.db.get_value }): 48 | self.status = s[0] 49 | break 50 | elif getattr(self, s[1])(): 51 | self.status = s[0] 52 | break 53 | 54 | if self.status != _status and self.status not in ("Cancelled", "Partially Ordered", 55 | "Ordered", "Issued", "Transferred"): 56 | self.add_comment("Label", _(self.status)) 57 | 58 | if update: 59 | self.db_set('status', self.status, update_modified = update_modified) 60 | -------------------------------------------------------------------------------- /posawesome/posawesome/api/taxes.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2023, Youssef Restom and contributors 3 | # For license information, please see license.txt 4 | 5 | 6 | from __future__ import unicode_literals 7 | 8 | # import frappe 9 | from frappe.utils import flt 10 | from erpnext.controllers.taxes_and_totals import calculate_taxes_and_totals 11 | from erpnext.accounts.doctype.sales_invoice.sales_invoice import SalesInvoice 12 | 13 | 14 | class custom_calculate_taxes_and_totals(calculate_taxes_and_totals): 15 | def _get_tax_rate(self, tax, item_tax_map): 16 | if tax.account_head in item_tax_map: 17 | return flt(item_tax_map.get(tax.account_head), self.doc.precision("rate", tax)) 18 | else: 19 | return 0 20 | 21 | 22 | class customSalesInvoice(SalesInvoice): 23 | def calculate_taxes_and_totals(object): 24 | return custom_calculate_taxes_and_totals(object) 25 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/posawesome/doctype/__init__.py -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/delivery_charges/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/posawesome/doctype/delivery_charges/__init__.py -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/delivery_charges/delivery_charges.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, Youssef Restom and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Delivery Charges', { 5 | setup: function (frm) { 6 | frm.set_query("shipping_account", function (doc) { 7 | return { 8 | filters: { 'company': doc.company } 9 | }; 10 | }); 11 | frm.set_query("cost_center", function (doc) { 12 | return { 13 | filters: { 'company': doc.company } 14 | }; 15 | }); 16 | frm.set_query("pos_profile", "profiles", function (doc) { 17 | return { 18 | filters: { 'company': doc.company } 19 | }; 20 | }); 21 | }, 22 | }); 23 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/delivery_charges/delivery_charges.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "allow_rename": 1, 4 | "autoname": "field:label", 5 | "creation": "2022-07-23 14:23:06.194196", 6 | "doctype": "DocType", 7 | "editable_grid": 1, 8 | "engine": "InnoDB", 9 | "field_order": [ 10 | "label", 11 | "company", 12 | "default_rate", 13 | "disabled", 14 | "column_break_3", 15 | "shipping_account", 16 | "cost_center", 17 | "apply_for_pos_profile_section", 18 | "profiles", 19 | "profiles_list" 20 | ], 21 | "fields": [ 22 | { 23 | "default": "0", 24 | "fieldname": "disabled", 25 | "fieldtype": "Check", 26 | "label": "Disabled" 27 | }, 28 | { 29 | "fieldname": "column_break_3", 30 | "fieldtype": "Column Break" 31 | }, 32 | { 33 | "fieldname": "company", 34 | "fieldtype": "Link", 35 | "in_list_view": 1, 36 | "label": "Company", 37 | "options": "Company", 38 | "reqd": 1 39 | }, 40 | { 41 | "fieldname": "default_rate", 42 | "fieldtype": "Currency", 43 | "label": "Default Rate", 44 | "non_negative": 1, 45 | "options": "currency", 46 | "reqd": 1 47 | }, 48 | { 49 | "fieldname": "shipping_account", 50 | "fieldtype": "Link", 51 | "label": "Shipping Account", 52 | "options": "Account", 53 | "reqd": 1 54 | }, 55 | { 56 | "fieldname": "cost_center", 57 | "fieldtype": "Link", 58 | "label": "Cost Center", 59 | "options": "Cost Center", 60 | "reqd": 1 61 | }, 62 | { 63 | "fieldname": "label", 64 | "fieldtype": "Data", 65 | "in_list_view": 1, 66 | "label": "Label", 67 | "reqd": 1, 68 | "unique": 1 69 | }, 70 | { 71 | "fieldname": "apply_for_pos_profile_section", 72 | "fieldtype": "Section Break", 73 | "label": "Apply For POS Profiles" 74 | }, 75 | { 76 | "fieldname": "profiles", 77 | "fieldtype": "Table", 78 | "label": "POS Profiles", 79 | "options": "Delivery Charges POS Profile" 80 | }, 81 | { 82 | "fieldname": "profiles_list", 83 | "fieldtype": "Code", 84 | "hidden": 1, 85 | "label": "Profiles List", 86 | "read_only": 1 87 | } 88 | ], 89 | "index_web_pages_for_search": 1, 90 | "links": [], 91 | "modified": "2022-07-25 15:38:25.771590", 92 | "modified_by": "Administrator", 93 | "module": "POSAwesome", 94 | "name": "Delivery Charges", 95 | "owner": "Administrator", 96 | "permissions": [ 97 | { 98 | "create": 1, 99 | "delete": 1, 100 | "email": 1, 101 | "export": 1, 102 | "print": 1, 103 | "read": 1, 104 | "report": 1, 105 | "role": "System Manager", 106 | "share": 1, 107 | "write": 1 108 | } 109 | ], 110 | "sort_field": "modified", 111 | "sort_order": "DESC" 112 | } -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/delivery_charges/delivery_charges.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Youssef Restom and contributors 2 | # For license information, please see license.txt 3 | 4 | import frappe 5 | from frappe import _ 6 | import json 7 | from frappe.model.document import Document 8 | 9 | 10 | class DeliveryCharges(Document): 11 | def validate(self): 12 | if not self.default_rate or self.default_rate <= 0: 13 | frappe.throw(_("Default Rate is required")) 14 | self.validate_profiles() 15 | 16 | def validate_profiles(self): 17 | profiles = [] 18 | for row in self.profiles: 19 | if row.pos_profile not in profiles: 20 | profiles.append(row.pos_profile) 21 | else: 22 | frappe.throw("Duplicate POS Profile in Delivery Charges") 23 | self.set_profiles_list(profiles) 24 | 25 | def set_profiles_list(self, profiles_list): 26 | if len(profiles_list) > 0: 27 | self.profiles_list = json.dumps(profiles_list) 28 | else: 29 | self.profiles_list = None 30 | 31 | 32 | def get_applicable_delivery_charges( 33 | company, 34 | pos_profile=None, 35 | customer=None, 36 | address=None, 37 | delivery_charges=None, 38 | restrict=False, 39 | ): 40 | charges = [] 41 | address_list = [] 42 | delivery_charges_list = [] 43 | if address: 44 | address_list.append(address) 45 | if customer: 46 | address_list.extend( 47 | frappe.get_all( 48 | "Dynamic Link", 49 | filters={ 50 | "link_doctype": "Customer", 51 | "link_name": customer, 52 | "parentfield": "links", 53 | "parenttype": "Address", 54 | }, 55 | pluck="parent", 56 | ) 57 | ) 58 | for address in address_list: 59 | address_charges = frappe.get_cached_value( 60 | "Address", address, "posa_delivery_charges" 61 | ) 62 | if address_charges: 63 | delivery_charges_list.append(address_charges) 64 | 65 | delivery_charges_filters = {"disabled": 0, "company": company} 66 | if delivery_charges: 67 | delivery_charges_list.append(delivery_charges) 68 | 69 | if len(delivery_charges_list) > 0: 70 | delivery_charges_filters["name"] = ["in", delivery_charges_list] 71 | if restrict: 72 | delivery_charges_filters["profiles_list"] = ["not in", ["", None]] 73 | 74 | delivery_charges_items = frappe.get_all( 75 | "Delivery Charges", 76 | filters=delivery_charges_filters, 77 | fields=["*"], 78 | ) 79 | delivery_charges_list = [i.name for i in delivery_charges_items] 80 | 81 | delivery_profiels_filters = {"parent": ("in", delivery_charges_list)} 82 | if pos_profile: 83 | delivery_profiels_filters["pos_profile"] = pos_profile 84 | delivery_profiels = frappe.get_all( 85 | "Delivery Charges POS Profile", 86 | filters=delivery_profiels_filters, 87 | fields=["*"], 88 | ) 89 | for charge in delivery_charges_items: 90 | profile = next((i for i in delivery_profiels if i.parent == charge.name), None) 91 | if profile: 92 | charge.rate = profile.rate 93 | charges.append(charge) 94 | else: 95 | if not restrict: 96 | if not charge.profiles_list: 97 | charge.rate = charge.default_rate 98 | charges.append(charge) 99 | 100 | return charges 101 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/delivery_charges/test_delivery_charges.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Youssef Restom and Contributors 2 | # See license.txt 3 | 4 | # import frappe 5 | import unittest 6 | 7 | class TestDeliveryCharges(unittest.TestCase): 8 | pass 9 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/delivery_charges_pos_profile/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/posawesome/doctype/delivery_charges_pos_profile/__init__.py -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/delivery_charges_pos_profile/delivery_charges_pos_profile.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "allow_rename": 1, 4 | "creation": "2022-07-23 15:06:07.819645", 5 | "doctype": "DocType", 6 | "editable_grid": 1, 7 | "engine": "InnoDB", 8 | "field_order": [ 9 | "pos_profile", 10 | "rate" 11 | ], 12 | "fields": [ 13 | { 14 | "fieldname": "pos_profile", 15 | "fieldtype": "Link", 16 | "in_list_view": 1, 17 | "label": "POS Profile", 18 | "options": "POS Profile", 19 | "reqd": 1 20 | }, 21 | { 22 | "fieldname": "rate", 23 | "fieldtype": "Currency", 24 | "in_list_view": 1, 25 | "label": "Rate", 26 | "options": "currency" 27 | } 28 | ], 29 | "index_web_pages_for_search": 1, 30 | "istable": 1, 31 | "links": [], 32 | "modified": "2022-07-24 16:29:28.981655", 33 | "modified_by": "Administrator", 34 | "module": "POSAwesome", 35 | "name": "Delivery Charges POS Profile", 36 | "owner": "Administrator", 37 | "permissions": [], 38 | "sort_field": "modified", 39 | "sort_order": "DESC" 40 | } -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/delivery_charges_pos_profile/delivery_charges_pos_profile.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Youssef Restom and contributors 2 | # For license information, please see license.txt 3 | 4 | # import frappe 5 | from frappe.model.document import Document 6 | 7 | class DeliveryChargesPOSProfile(Document): 8 | pass 9 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/mpesa_c2b_register_url/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/posawesome/doctype/mpesa_c2b_register_url/__init__.py -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/mpesa_c2b_register_url/mpesa_c2b_register_url.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021, Youssef Restom and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Mpesa C2B Register URL', { 5 | // refresh: function(frm) { 6 | 7 | // } 8 | }); 9 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/mpesa_c2b_register_url/mpesa_c2b_register_url.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "autoname": "field:mpesa_settings", 4 | "creation": "2021-11-10 03:59:38.274817", 5 | "doctype": "DocType", 6 | "editable_grid": 1, 7 | "engine": "InnoDB", 8 | "field_order": [ 9 | "mpesa_settings", 10 | "till_number", 11 | "business_shortcode", 12 | "column_break_4", 13 | "company", 14 | "mode_of_payment", 15 | "register_status" 16 | ], 17 | "fields": [ 18 | { 19 | "fieldname": "mpesa_settings", 20 | "fieldtype": "Link", 21 | "in_list_view": 1, 22 | "label": "Mpesa Settings", 23 | "options": "Mpesa Settings", 24 | "reqd": 1, 25 | "unique": 1 26 | }, 27 | { 28 | "fetch_from": "mpesa_settings.till_number", 29 | "fieldname": "till_number", 30 | "fieldtype": "Data", 31 | "label": "Till Number", 32 | "read_only": 1 33 | }, 34 | { 35 | "fetch_from": "mpesa_settings.business_shortcode", 36 | "fieldname": "business_shortcode", 37 | "fieldtype": "Data", 38 | "label": "Business Shortcode", 39 | "read_only": 1 40 | }, 41 | { 42 | "fieldname": "column_break_4", 43 | "fieldtype": "Column Break" 44 | }, 45 | { 46 | "fieldname": "mode_of_payment", 47 | "fieldtype": "Link", 48 | "in_list_view": 1, 49 | "in_standard_filter": 1, 50 | "label": "Mode of Payment", 51 | "options": "Mode of Payment", 52 | "reqd": 1 53 | }, 54 | { 55 | "default": "Pending", 56 | "fieldname": "register_status", 57 | "fieldtype": "Select", 58 | "in_list_view": 1, 59 | "in_standard_filter": 1, 60 | "label": "Register Status", 61 | "options": "Pending\nSuccess\nFailed", 62 | "read_only": 1 63 | }, 64 | { 65 | "fieldname": "company", 66 | "fieldtype": "Link", 67 | "in_list_view": 1, 68 | "in_standard_filter": 1, 69 | "label": "Company", 70 | "options": "Company", 71 | "reqd": 1 72 | } 73 | ], 74 | "index_web_pages_for_search": 1, 75 | "links": [], 76 | "modified": "2023-06-07 17:56:04.569137", 77 | "modified_by": "Administrator", 78 | "module": "POSAwesome", 79 | "name": "Mpesa C2B Register URL", 80 | "naming_rule": "By fieldname", 81 | "owner": "Administrator", 82 | "permissions": [ 83 | { 84 | "create": 1, 85 | "delete": 1, 86 | "email": 1, 87 | "export": 1, 88 | "print": 1, 89 | "read": 1, 90 | "report": 1, 91 | "role": "System Manager", 92 | "share": 1, 93 | "write": 1 94 | }, 95 | { 96 | "create": 1, 97 | "delete": 1, 98 | "email": 1, 99 | "export": 1, 100 | "print": 1, 101 | "read": 1, 102 | "report": 1, 103 | "role": "Accounts Manager", 104 | "share": 1, 105 | "write": 1 106 | }, 107 | { 108 | "email": 1, 109 | "export": 1, 110 | "print": 1, 111 | "read": 1, 112 | "report": 1, 113 | "role": "Accounts User", 114 | "share": 1 115 | }, 116 | { 117 | "email": 1, 118 | "export": 1, 119 | "print": 1, 120 | "read": 1, 121 | "report": 1, 122 | "role": "Sales User", 123 | "share": 1 124 | } 125 | ], 126 | "sort_field": "modified", 127 | "sort_order": "DESC", 128 | "states": [], 129 | "track_changes": 1 130 | } -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/mpesa_c2b_register_url/mpesa_c2b_register_url.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Youssef Restom and contributors 2 | # For license information, please see license.txt 3 | 4 | import frappe, requests 5 | from frappe.model.document import Document 6 | from frappe.utils import get_request_site_address 7 | from posawesome.posawesome.api.m_pesa import get_token 8 | 9 | 10 | class MpesaC2BRegisterURL(Document): 11 | def validate(self): 12 | sandbox_url = "https://sandbox.safaricom.co.ke" 13 | live_url = "https://api.safaricom.co.ke" 14 | mpesa_settings = frappe.get_doc("Mpesa Settings", self.mpesa_settings) 15 | env = "production" if not mpesa_settings.sandbox else "sandbox" 16 | business_shortcode = ( 17 | mpesa_settings.business_shortcode 18 | if env == "production" 19 | else mpesa_settings.till_number 20 | ) 21 | if env == "sandbox": 22 | base_url = sandbox_url 23 | else: 24 | base_url = live_url 25 | token = get_token( 26 | app_key=mpesa_settings.consumer_key, 27 | app_secret=mpesa_settings.get_password("consumer_secret"), 28 | base_url=base_url, 29 | ) 30 | site_url = get_request_site_address(True) 31 | validation_url = ( 32 | site_url + "/api/method/posawesome.posawesome.api.m_pesa.validation" 33 | ) 34 | confirmation_url = ( 35 | site_url + "/api/method/posawesome.posawesome.api.m_pesa.confirmation" 36 | ) 37 | register_url = base_url + "/mpesa/c2b/v2/registerurl" 38 | 39 | payload = { 40 | "ShortCode": business_shortcode, 41 | "ResponseType": "Completed", 42 | "ConfirmationURL": confirmation_url, 43 | "ValidationURL": validation_url, 44 | } 45 | headers = { 46 | "Authorization": "Bearer {0}".format(token), 47 | "Content-Type": "application/json", 48 | } 49 | r = requests.post(register_url, headers=headers, json=payload) 50 | res = r.json() 51 | if res.get("ResponseDescription") == "Success": 52 | self.register_status = "Success" 53 | else: 54 | self.register_status = "Failed" 55 | frappe.msgprint(str(res)) 56 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/mpesa_c2b_register_url/test_mpesa_c2b_register_url.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Youssef Restom and Contributors 2 | # See license.txt 3 | 4 | # import frappe 5 | import unittest 6 | 7 | class TestMpesaC2BRegisterURL(unittest.TestCase): 8 | pass 9 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/mpesa_payment_register/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/posawesome/doctype/mpesa_payment_register/__init__.py -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/mpesa_payment_register/mpesa_payment_register.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021, Youssef Restom and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Mpesa Payment Register', { 5 | // refresh: function(frm) { 6 | 7 | // } 8 | }); 9 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/mpesa_payment_register/mpesa_payment_register.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "allow_copy": 1, 4 | "autoname": "MPRE.-.YY.-.MM.-.######", 5 | "creation": "2021-11-10 03:47:20.144127", 6 | "doctype": "DocType", 7 | "editable_grid": 1, 8 | "engine": "InnoDB", 9 | "field_order": [ 10 | "full_name", 11 | "transactiontype", 12 | "transid", 13 | "transtime", 14 | "transamount", 15 | "businessshortcode", 16 | "billrefnumber", 17 | "invoicenumber", 18 | "orgaccountbalance", 19 | "thirdpartytransid", 20 | "msisdn", 21 | "firstname", 22 | "middlename", 23 | "lastname", 24 | "column_break_14", 25 | "posting_date", 26 | "posting_time", 27 | "company", 28 | "default_currency", 29 | "customer", 30 | "mode_of_payment", 31 | "currency", 32 | "submit_payment", 33 | "payment_entry", 34 | "amended_from" 35 | ], 36 | "fields": [ 37 | { 38 | "fieldname": "transactiontype", 39 | "fieldtype": "Data", 40 | "label": "Transaction Type", 41 | "no_copy": 1, 42 | "read_only": 1 43 | }, 44 | { 45 | "fieldname": "transid", 46 | "fieldtype": "Data", 47 | "label": "Trans ID", 48 | "no_copy": 1, 49 | "read_only": 1 50 | }, 51 | { 52 | "fieldname": "transtime", 53 | "fieldtype": "Data", 54 | "label": "Trans Time", 55 | "no_copy": 1, 56 | "read_only": 1 57 | }, 58 | { 59 | "fieldname": "transamount", 60 | "fieldtype": "Float", 61 | "in_list_view": 1, 62 | "in_preview": 1, 63 | "in_standard_filter": 1, 64 | "label": "Trans Amount", 65 | "no_copy": 1, 66 | "read_only": 1 67 | }, 68 | { 69 | "fieldname": "businessshortcode", 70 | "fieldtype": "Data", 71 | "in_list_view": 1, 72 | "in_standard_filter": 1, 73 | "label": "Business Short Code", 74 | "no_copy": 1, 75 | "read_only": 1 76 | }, 77 | { 78 | "fieldname": "billrefnumber", 79 | "fieldtype": "Data", 80 | "label": "Bill Ref Number", 81 | "no_copy": 1, 82 | "read_only": 1 83 | }, 84 | { 85 | "fieldname": "invoicenumber", 86 | "fieldtype": "Data", 87 | "label": "Invoice Number", 88 | "no_copy": 1, 89 | "read_only": 1 90 | }, 91 | { 92 | "fieldname": "orgaccountbalance", 93 | "fieldtype": "Data", 94 | "label": "Org Account Balance", 95 | "no_copy": 1, 96 | "read_only": 1 97 | }, 98 | { 99 | "fieldname": "thirdpartytransid", 100 | "fieldtype": "Data", 101 | "label": "Third Party Trans ID", 102 | "no_copy": 1, 103 | "read_only": 1 104 | }, 105 | { 106 | "fieldname": "msisdn", 107 | "fieldtype": "Data", 108 | "in_list_view": 1, 109 | "in_preview": 1, 110 | "in_standard_filter": 1, 111 | "label": "MSISDN", 112 | "no_copy": 1, 113 | "options": "Phone", 114 | "read_only": 1 115 | }, 116 | { 117 | "fieldname": "firstname", 118 | "fieldtype": "Data", 119 | "in_preview": 1, 120 | "in_standard_filter": 1, 121 | "label": "First Name", 122 | "no_copy": 1, 123 | "read_only": 1 124 | }, 125 | { 126 | "fieldname": "middlename", 127 | "fieldtype": "Data", 128 | "label": "Middle Name", 129 | "no_copy": 1, 130 | "read_only": 1 131 | }, 132 | { 133 | "fieldname": "lastname", 134 | "fieldtype": "Data", 135 | "in_preview": 1, 136 | "in_standard_filter": 1, 137 | "label": "Last Name", 138 | "no_copy": 1, 139 | "read_only": 1 140 | }, 141 | { 142 | "fieldname": "column_break_14", 143 | "fieldtype": "Column Break" 144 | }, 145 | { 146 | "fieldname": "company", 147 | "fieldtype": "Link", 148 | "label": "Company", 149 | "options": "Company" 150 | }, 151 | { 152 | "fieldname": "customer", 153 | "fieldtype": "Link", 154 | "in_list_view": 1, 155 | "in_preview": 1, 156 | "in_standard_filter": 1, 157 | "label": "Customer", 158 | "options": "Customer" 159 | }, 160 | { 161 | "default": "Today", 162 | "fieldname": "posting_date", 163 | "fieldtype": "Date", 164 | "in_list_view": 1, 165 | "in_preview": 1, 166 | "in_standard_filter": 1, 167 | "label": "Posting Date", 168 | "no_copy": 1, 169 | "read_only": 1 170 | }, 171 | { 172 | "fieldname": "payment_entry", 173 | "fieldtype": "Link", 174 | "label": "Payment Entry", 175 | "options": "Payment Entry", 176 | "read_only": 1 177 | }, 178 | { 179 | "fetch_from": "company.default_currency", 180 | "fieldname": "default_currency", 181 | "fieldtype": "Data", 182 | "label": "Default Currency", 183 | "read_only": 1 184 | }, 185 | { 186 | "fieldname": "amended_from", 187 | "fieldtype": "Link", 188 | "label": "Amended From", 189 | "no_copy": 1, 190 | "options": "Mpesa Payment Register", 191 | "print_hide": 1, 192 | "read_only": 1 193 | }, 194 | { 195 | "fieldname": "mode_of_payment", 196 | "fieldtype": "Link", 197 | "label": "Mode of Payment", 198 | "options": "Mode of Payment" 199 | }, 200 | { 201 | "default": "KES", 202 | "fieldname": "currency", 203 | "fieldtype": "Link", 204 | "label": "Currency", 205 | "options": "Currency", 206 | "read_only": 1 207 | }, 208 | { 209 | "fieldname": "full_name", 210 | "fieldtype": "Data", 211 | "in_list_view": 1, 212 | "in_standard_filter": 1, 213 | "label": "Full Name", 214 | "no_copy": 1, 215 | "read_only": 1 216 | }, 217 | { 218 | "default": "0", 219 | "fieldname": "submit_payment", 220 | "fieldtype": "Check", 221 | "label": "Submit Payment " 222 | }, 223 | { 224 | "default": "Now", 225 | "fieldname": "posting_time", 226 | "fieldtype": "Time", 227 | "label": "Posting Time", 228 | "no_copy": 1, 229 | "read_only": 1 230 | } 231 | ], 232 | "in_create": 1, 233 | "index_web_pages_for_search": 1, 234 | "is_submittable": 1, 235 | "links": [], 236 | "modified": "2023-06-07 22:24:09.518620", 237 | "modified_by": "Administrator", 238 | "module": "POSAwesome", 239 | "name": "Mpesa Payment Register", 240 | "naming_rule": "Expression (old style)", 241 | "owner": "Administrator", 242 | "permissions": [ 243 | { 244 | "delete": 1, 245 | "email": 1, 246 | "export": 1, 247 | "print": 1, 248 | "read": 1, 249 | "report": 1, 250 | "role": "System Manager", 251 | "share": 1, 252 | "write": 1 253 | }, 254 | { 255 | "email": 1, 256 | "export": 1, 257 | "print": 1, 258 | "read": 1, 259 | "report": 1, 260 | "role": "Accounts User", 261 | "share": 1, 262 | "submit": 1, 263 | "write": 1 264 | }, 265 | { 266 | "amend": 1, 267 | "cancel": 1, 268 | "email": 1, 269 | "export": 1, 270 | "print": 1, 271 | "read": 1, 272 | "report": 1, 273 | "role": "Accounts Manager", 274 | "share": 1, 275 | "submit": 1, 276 | "write": 1 277 | }, 278 | { 279 | "email": 1, 280 | "export": 1, 281 | "print": 1, 282 | "read": 1, 283 | "report": 1, 284 | "role": "Sales User", 285 | "share": 1, 286 | "submit": 1, 287 | "write": 1 288 | } 289 | ], 290 | "show_preview_popup": 1, 291 | "sort_field": "modified", 292 | "sort_order": "DESC", 293 | "states": [], 294 | "title_field": "customer", 295 | "track_changes": 1 296 | } -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/mpesa_payment_register/mpesa_payment_register.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Youssef Restom and contributors 2 | # For license information, please see license.txt 3 | 4 | import frappe 5 | from frappe import _ 6 | from frappe.model.document import Document 7 | from posawesome.posawesome.api.payment_entry import create_payment_entry 8 | 9 | 10 | class MpesaPaymentRegister(Document): 11 | def before_insert(self): 12 | self.set_missing_values() 13 | 14 | def set_missing_values(self): 15 | self.currency = "KES" 16 | self.full_name = "" 17 | if self.firstname: 18 | self.full_name = self.firstname 19 | if self.middlename: 20 | self.full_name += " " + self.middlename 21 | if self.lastname: 22 | self.full_name += " " + self.lastname 23 | 24 | register_url_list = frappe.get_all( 25 | "Mpesa C2B Register URL", 26 | filters={ 27 | "business_shortcode": self.businessshortcode, 28 | "register_status": "Success", 29 | }, 30 | fields=["company", "mode_of_payment"], 31 | ) 32 | if len(register_url_list) > 0: 33 | self.company = register_url_list[0].company 34 | self.mode_of_payment = register_url_list[0].mode_of_payment 35 | 36 | def before_submit(self): 37 | if not self.transamount: 38 | frappe.throw(_("Trans Amount is required")) 39 | if not self.company: 40 | frappe.throw(_("Company is required")) 41 | if not self.customer: 42 | frappe.throw(_("Customer is required")) 43 | if not self.mode_of_payment: 44 | frappe.throw(_("Mode of Payment is required")) 45 | self.payment_entry = self.create_payment_entry() 46 | 47 | def create_payment_entry(self): 48 | payment_entry = create_payment_entry( 49 | self.company, 50 | self.customer, 51 | self.transamount, 52 | self.currency, 53 | self.mode_of_payment, 54 | self.posting_date, 55 | self.transid, 56 | self.posting_date, 57 | None, 58 | self.submit_payment, 59 | ) 60 | return payment_entry.name 61 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/mpesa_payment_register/test_mpesa_payment_register.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Youssef Restom and Contributors 2 | # See license.txt 3 | 4 | # import frappe 5 | import unittest 6 | 7 | class TestMpesaPaymentRegister(unittest.TestCase): 8 | pass 9 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_closing_shift/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/posawesome/doctype/pos_closing_shift/__init__.py -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_closing_shift/closing_shift_details.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 | 7 |
8 |
{{ _("Sales Summary") }}
9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
{{ _('Grand Total') }} {{ frappe.utils.fmt_money(data.grand_total or '', currency=currency) }}
{{ _('Net Total') }} {{ frappe.utils.fmt_money(data.net_total or '', currency=currency) }}
{{ _('Total Quantity') }}{{ data.total_quantity or '' }}
29 |
30 |
31 | 32 | 33 | 34 |
35 |
{{ _("Mode of Payments") }}
36 |
37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | {% for d in data.payment_reconciliation %} 46 | 47 | 48 | 49 | 50 | {% endfor %} 51 | 52 |
{{ _("Mode of Payment") }}{{ _("Amount") }}
{{ d.mode_of_payment }} {{ frappe.utils.fmt_money(d.expected_amount - d.opening_amount, currency=currency) }}
53 |
54 |
55 | 56 | 57 | 58 | {% if data.taxes %} 59 |
60 |
{{ _("Taxes") }}
61 |
62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | {% for d in data.taxes %} 72 | 73 | 74 | 75 | 76 | 77 | {% endfor %} 78 | 79 |
{{ _("Account") }}{{ _("Rate") }}{{ _("Amount") }}
{{ d.account_head }}{{ d.rate }} % {{ frappe.utils.fmt_money(d.amount, currency=currency) }}
80 |
81 |
82 | {% endif %} 83 | 84 | 85 |
86 |
87 |
88 | 89 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_closing_shift/pos_closing_shift.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Youssef Restom and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('POS Closing Shift', { 5 | onload: function (frm) { 6 | frm.set_query("pos_profile", function (doc) { 7 | return { 8 | filters: { 'user': doc.user } 9 | }; 10 | }); 11 | 12 | frm.set_query("user", function (doc) { 13 | return { 14 | query: "posawesome.posawesome.doctype.pos_closing_shift.pos_closing_shift.get_cashiers", 15 | filters: { 'parent': doc.pos_profile } 16 | }; 17 | }); 18 | 19 | frm.set_query("pos_opening_shift", function (doc) { 20 | return { filters: { 'status': 'Open', 'docstatus': 1 } }; 21 | }); 22 | 23 | if (frm.doc.docstatus === 0) frm.set_value("period_end_date", frappe.datetime.now_datetime()); 24 | if (frm.doc.docstatus === 1) set_html_data(frm); 25 | }, 26 | 27 | pos_opening_shift (frm) { 28 | if (frm.doc.pos_opening_shift && frm.doc.user) { 29 | reset_values(frm); 30 | frappe.run_serially([ 31 | () => frm.trigger("set_opening_amounts"), 32 | () => frm.trigger("get_pos_invoices"), 33 | () => frm.trigger("get_pos_payments") 34 | ]); 35 | } 36 | }, 37 | 38 | set_opening_amounts (frm) { 39 | frappe.db.get_doc("POS Opening Shift", frm.doc.pos_opening_shift) 40 | .then(({ balance_details }) => { 41 | balance_details.forEach(detail => { 42 | frm.add_child("payment_reconciliation", { 43 | mode_of_payment: detail.mode_of_payment, 44 | opening_amount: detail.amount || 0, 45 | expected_amount: detail.amount || 0 46 | }); 47 | }); 48 | }); 49 | }, 50 | 51 | get_pos_invoices (frm) { 52 | frappe.call({ 53 | method: 'posawesome.posawesome.doctype.pos_closing_shift.pos_closing_shift.get_pos_invoices', 54 | args: { 55 | pos_opening_shift: frm.doc.pos_opening_shift, 56 | }, 57 | callback: (r) => { 58 | let pos_docs = r.message; 59 | set_form_data(pos_docs, frm); 60 | refresh_fields(frm); 61 | set_html_data(frm); 62 | } 63 | }); 64 | }, 65 | 66 | get_pos_payments (frm) { 67 | frappe.call({ 68 | method: 'posawesome.posawesome.doctype.pos_closing_shift.pos_closing_shift.get_payments_entries', 69 | args: { 70 | pos_opening_shift: frm.doc.pos_opening_shift, 71 | }, 72 | callback: (r) => { 73 | let pos_payments = r.message; 74 | set_form_payments_data(pos_payments, frm); 75 | refresh_fields(frm); 76 | set_html_data(frm); 77 | } 78 | }); 79 | } 80 | }); 81 | 82 | frappe.ui.form.on('POS Closing Shift Detail', { 83 | closing_amount: (frm, cdt, cdn) => { 84 | const row = locals[cdt][cdn]; 85 | frappe.model.set_value(cdt, cdn, "difference", flt(row.expected_amount - row.closing_amount)); 86 | } 87 | }); 88 | 89 | function set_form_data (data, frm) { 90 | data.forEach(d => { 91 | add_to_pos_transaction(d, frm); 92 | frm.doc.grand_total += flt(d.grand_total); 93 | frm.doc.net_total += flt(d.net_total); 94 | frm.doc.total_quantity += flt(d.total_qty); 95 | add_to_payments(d, frm); 96 | add_to_taxes(d, frm); 97 | }); 98 | } 99 | 100 | function set_form_payments_data (data, frm) { 101 | data.forEach(d => { 102 | add_to_pos_payments(d, frm); 103 | add_pos_payment_to_payments(d, frm); 104 | }); 105 | } 106 | 107 | function add_to_pos_transaction (d, frm) { 108 | frm.add_child("pos_transactions", { 109 | sales_invoice: d.name, 110 | posting_date: d.posting_date, 111 | grand_total: d.grand_total, 112 | customer: d.customer 113 | }); 114 | } 115 | 116 | function add_to_pos_payments (d, frm) { 117 | frm.add_child("pos_payments", { 118 | payment_entry: d.name, 119 | posting_date: d.posting_date, 120 | paid_amount: d.paid_amount, 121 | customer: d.party, 122 | mode_of_payment: d.mode_of_payment 123 | }); 124 | } 125 | 126 | function add_to_payments (d, frm) { 127 | d.payments.forEach(p => { 128 | const payment = frm.doc.payment_reconciliation.find(pay => pay.mode_of_payment === p.mode_of_payment); 129 | if (payment) { 130 | let amount = p.amount; 131 | let cash_mode_of_payment = get_value("POS Profile", frm.doc.pos_profile, 'posa_cash_mode_of_payment'); 132 | if (!cash_mode_of_payment) { 133 | cash_mode_of_payment = 'Cash'; 134 | } 135 | if (payment.mode_of_payment == cash_mode_of_payment) { 136 | amount = p.amount - d.change_amount; 137 | } 138 | payment.expected_amount += flt(amount); 139 | } else { 140 | frm.add_child("payment_reconciliation", { 141 | mode_of_payment: p.mode_of_payment, 142 | opening_amount: 0, 143 | expected_amount: p.amount || 0 144 | }); 145 | } 146 | }); 147 | } 148 | 149 | function add_pos_payment_to_payments (p, frm) { 150 | const payment = frm.doc.payment_reconciliation.find(pay => pay.mode_of_payment === p.mode_of_payment); 151 | if (payment) { 152 | let amount = p.paid_amount; 153 | payment.expected_amount += flt(amount); 154 | } else { 155 | frm.add_child("payment_reconciliation", { 156 | mode_of_payment: p.mode_of_payment, 157 | opening_amount: 0, 158 | expected_amount: p.amount || 0 159 | }); 160 | } 161 | }; 162 | 163 | 164 | function add_to_taxes (d, frm) { 165 | d.taxes.forEach(t => { 166 | const tax = frm.doc.taxes.find(tx => tx.account_head === t.account_head && tx.rate === t.rate); 167 | if (tax) { 168 | tax.amount += flt(t.tax_amount); 169 | } else { 170 | frm.add_child("taxes", { 171 | account_head: t.account_head, 172 | rate: t.rate, 173 | amount: t.tax_amount 174 | }); 175 | } 176 | }); 177 | } 178 | 179 | function reset_values (frm) { 180 | frm.set_value("pos_transactions", []); 181 | frm.set_value("payment_reconciliation", []); 182 | frm.set_value("pos_payments", []); 183 | frm.set_value("taxes", []); 184 | frm.set_value("grand_total", 0); 185 | frm.set_value("net_total", 0); 186 | frm.set_value("total_quantity", 0); 187 | } 188 | 189 | function refresh_fields (frm) { 190 | frm.refresh_field("pos_transactions"); 191 | frm.refresh_field("payment_reconciliation"); 192 | frm.refresh_field("pos_payments"); 193 | frm.refresh_field("taxes"); 194 | frm.refresh_field("grand_total"); 195 | frm.refresh_field("net_total"); 196 | frm.refresh_field("total_quantity"); 197 | } 198 | 199 | function set_html_data (frm) { 200 | frappe.call({ 201 | method: "get_payment_reconciliation_details", 202 | doc: frm.doc, 203 | callback: (r) => { 204 | frm.get_field("payment_reconciliation_details").$wrapper.html(r.message); 205 | } 206 | }); 207 | } 208 | 209 | const get_value = (doctype, name, field) => { 210 | let value; 211 | frappe.call({ 212 | method: 'frappe.client.get_value', 213 | args: { 214 | 'doctype': doctype, 215 | 'filters': { 'name': name }, 216 | 'fieldname': field 217 | }, 218 | async: false, 219 | callback: function (r) { 220 | if (!r.exc) { 221 | value = r.message[field]; 222 | } 223 | } 224 | }); 225 | return value; 226 | }; -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_closing_shift/pos_closing_shift.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "allow_copy": 1, 4 | "autoname": "POSA-CS-.YY.-.#######", 5 | "creation": "2020-09-29 02:38:20.917434", 6 | "doctype": "DocType", 7 | "editable_grid": 1, 8 | "engine": "InnoDB", 9 | "field_order": [ 10 | "period_start_date", 11 | "period_end_date", 12 | "column_break_3", 13 | "posting_date", 14 | "pos_opening_shift", 15 | "section_break_5", 16 | "company", 17 | "column_break_7", 18 | "pos_profile", 19 | "user", 20 | "section_break_12", 21 | "pos_transactions", 22 | "section_break_9", 23 | "pos_payments", 24 | "section_break_if3m1", 25 | "payment_reconciliation_details", 26 | "section_break_11", 27 | "payment_reconciliation", 28 | "section_break_13", 29 | "grand_total", 30 | "net_total", 31 | "total_quantity", 32 | "column_break_16", 33 | "taxes", 34 | "section_break_14", 35 | "amended_from" 36 | ], 37 | "fields": [ 38 | { 39 | "fetch_from": "pos_opening_shift.period_start_date", 40 | "fieldname": "period_start_date", 41 | "fieldtype": "Datetime", 42 | "in_list_view": 1, 43 | "label": "Period Start Date", 44 | "read_only": 1, 45 | "reqd": 1 46 | }, 47 | { 48 | "default": "Today", 49 | "fieldname": "period_end_date", 50 | "fieldtype": "Datetime", 51 | "in_list_view": 1, 52 | "label": "Period End Date", 53 | "read_only": 1, 54 | "reqd": 1 55 | }, 56 | { 57 | "fieldname": "column_break_3", 58 | "fieldtype": "Column Break" 59 | }, 60 | { 61 | "default": "Today", 62 | "fieldname": "posting_date", 63 | "fieldtype": "Date", 64 | "in_list_view": 1, 65 | "label": "Posting Date", 66 | "reqd": 1 67 | }, 68 | { 69 | "fieldname": "section_break_5", 70 | "fieldtype": "Section Break" 71 | }, 72 | { 73 | "fieldname": "company", 74 | "fieldtype": "Link", 75 | "label": "Company", 76 | "options": "Company", 77 | "reqd": 1 78 | }, 79 | { 80 | "fieldname": "column_break_7", 81 | "fieldtype": "Column Break" 82 | }, 83 | { 84 | "fetch_from": "pos_opening_shift.pos_profile", 85 | "fieldname": "pos_profile", 86 | "fieldtype": "Link", 87 | "in_list_view": 1, 88 | "label": "POS Profile", 89 | "options": "POS Profile", 90 | "reqd": 1 91 | }, 92 | { 93 | "fetch_from": "pos_opening_shift.user", 94 | "fieldname": "user", 95 | "fieldtype": "Link", 96 | "label": "Cashier", 97 | "options": "User", 98 | "reqd": 1 99 | }, 100 | { 101 | "fieldname": "section_break_12", 102 | "fieldtype": "Section Break", 103 | "label": "Linked Invoices" 104 | }, 105 | { 106 | "fieldname": "pos_transactions", 107 | "fieldtype": "Table", 108 | "label": "POS Transactions", 109 | "options": "Sales Invoice Reference" 110 | }, 111 | { 112 | "fieldname": "section_break_9", 113 | "fieldtype": "Section Break", 114 | "read_only": 1 115 | }, 116 | { 117 | "depends_on": "eval:doc.docstatus==1", 118 | "fieldname": "payment_reconciliation_details", 119 | "fieldtype": "HTML" 120 | }, 121 | { 122 | "fieldname": "section_break_11", 123 | "fieldtype": "Section Break", 124 | "label": "Modes of Payment" 125 | }, 126 | { 127 | "fieldname": "payment_reconciliation", 128 | "fieldtype": "Table", 129 | "label": "Payment Reconciliation", 130 | "options": "POS Closing Shift Detail" 131 | }, 132 | { 133 | "collapsible": 1, 134 | "collapsible_depends_on": "eval:doc.docstatus==0", 135 | "fieldname": "section_break_13", 136 | "fieldtype": "Section Break", 137 | "label": "Details" 138 | }, 139 | { 140 | "default": "0", 141 | "fieldname": "grand_total", 142 | "fieldtype": "Currency", 143 | "label": "Grand Total", 144 | "read_only": 1 145 | }, 146 | { 147 | "default": "0", 148 | "fieldname": "net_total", 149 | "fieldtype": "Currency", 150 | "label": "Net Total", 151 | "read_only": 1 152 | }, 153 | { 154 | "fieldname": "total_quantity", 155 | "fieldtype": "Float", 156 | "label": "Total Quantity", 157 | "read_only": 1 158 | }, 159 | { 160 | "fieldname": "column_break_16", 161 | "fieldtype": "Column Break" 162 | }, 163 | { 164 | "fieldname": "taxes", 165 | "fieldtype": "Table", 166 | "label": "Taxes", 167 | "options": "POS Closing Shift Taxes", 168 | "read_only": 1 169 | }, 170 | { 171 | "fieldname": "section_break_14", 172 | "fieldtype": "Section Break" 173 | }, 174 | { 175 | "fieldname": "amended_from", 176 | "fieldtype": "Link", 177 | "label": "Amended From", 178 | "no_copy": 1, 179 | "options": "POS Closing Shift", 180 | "print_hide": 1, 181 | "read_only": 1 182 | }, 183 | { 184 | "fieldname": "pos_opening_shift", 185 | "fieldtype": "Link", 186 | "label": "POS Opening Shift", 187 | "options": "POS Opening Shift", 188 | "reqd": 1 189 | }, 190 | { 191 | "fieldname": "pos_payments", 192 | "fieldtype": "Table", 193 | "label": "POS Payments", 194 | "options": "POS Payment Entry Reference" 195 | }, 196 | { 197 | "fieldname": "section_break_if3m1", 198 | "fieldtype": "Section Break" 199 | } 200 | ], 201 | "is_submittable": 1, 202 | "links": [], 203 | "modified": "2023-06-12 03:01:49.146706", 204 | "modified_by": "Administrator", 205 | "module": "POSAwesome", 206 | "name": "POS Closing Shift", 207 | "naming_rule": "Expression (old style)", 208 | "owner": "Administrator", 209 | "permissions": [ 210 | { 211 | "cancel": 1, 212 | "create": 1, 213 | "delete": 1, 214 | "email": 1, 215 | "export": 1, 216 | "print": 1, 217 | "read": 1, 218 | "report": 1, 219 | "role": "System Manager", 220 | "share": 1, 221 | "submit": 1, 222 | "write": 1 223 | }, 224 | { 225 | "cancel": 1, 226 | "create": 1, 227 | "email": 1, 228 | "export": 1, 229 | "print": 1, 230 | "read": 1, 231 | "report": 1, 232 | "role": "Sales Manager", 233 | "share": 1, 234 | "submit": 1, 235 | "write": 1 236 | }, 237 | { 238 | "cancel": 1, 239 | "create": 1, 240 | "delete": 1, 241 | "email": 1, 242 | "export": 1, 243 | "print": 1, 244 | "read": 1, 245 | "report": 1, 246 | "role": "Administrator", 247 | "share": 1, 248 | "submit": 1, 249 | "write": 1 250 | } 251 | ], 252 | "sort_field": "modified", 253 | "sort_order": "DESC", 254 | "states": [], 255 | "track_changes": 1 256 | } -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_closing_shift/test_pos_closing_shift.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Youssef Restom and Contributors 3 | # See license.txt 4 | from __future__ import unicode_literals 5 | 6 | # import frappe 7 | import unittest 8 | 9 | class TestPOSClosingShift(unittest.TestCase): 10 | pass 11 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_closing_shift_detail/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/posawesome/doctype/pos_closing_shift_detail/__init__.py -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_closing_shift_detail/pos_closing_shift_detail.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "creation": "2020-09-29 02:59:27.107324", 4 | "doctype": "DocType", 5 | "editable_grid": 1, 6 | "engine": "InnoDB", 7 | "field_order": [ 8 | "mode_of_payment", 9 | "opening_amount", 10 | "closing_amount", 11 | "expected_amount", 12 | "difference" 13 | ], 14 | "fields": [ 15 | { 16 | "fieldname": "mode_of_payment", 17 | "fieldtype": "Link", 18 | "in_list_view": 1, 19 | "label": "Mode of Payment", 20 | "options": "Mode of Payment", 21 | "reqd": 1 22 | }, 23 | { 24 | "fieldname": "opening_amount", 25 | "fieldtype": "Currency", 26 | "in_list_view": 1, 27 | "label": "Opening Amount", 28 | "options": "company:company_currency", 29 | "read_only": 1, 30 | "reqd": 1 31 | }, 32 | { 33 | "fieldname": "closing_amount", 34 | "fieldtype": "Currency", 35 | "in_list_view": 1, 36 | "label": "Closing Amount", 37 | "options": "company:company_currency", 38 | "reqd": 1 39 | }, 40 | { 41 | "fieldname": "expected_amount", 42 | "fieldtype": "Currency", 43 | "in_list_view": 1, 44 | "label": "Expected Amount", 45 | "options": "company:company_currency", 46 | "read_only": 1, 47 | "reqd": 1 48 | }, 49 | { 50 | "fieldname": "difference", 51 | "fieldtype": "Currency", 52 | "in_list_view": 1, 53 | "label": "Difference", 54 | "options": "company:company_currency", 55 | "read_only": 1 56 | } 57 | ], 58 | "istable": 1, 59 | "links": [], 60 | "modified": "2020-09-29 02:59:35.699400", 61 | "modified_by": "Administrator", 62 | "module": "POSAwesome", 63 | "name": "POS Closing Shift Detail", 64 | "owner": "Administrator", 65 | "permissions": [], 66 | "quick_entry": 1, 67 | "sort_field": "modified", 68 | "sort_order": "DESC", 69 | "track_changes": 1 70 | } -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_closing_shift_detail/pos_closing_shift_detail.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Youssef Restom 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 POSClosingShiftDetail(Document): 10 | pass 11 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_closing_shift_taxes/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/posawesome/doctype/pos_closing_shift_taxes/__init__.py -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_closing_shift_taxes/pos_closing_shift_taxes.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "creation": "2020-09-29 03:00:46.321522", 4 | "doctype": "DocType", 5 | "editable_grid": 1, 6 | "engine": "InnoDB", 7 | "field_order": [ 8 | "account_head", 9 | "rate", 10 | "amount" 11 | ], 12 | "fields": [ 13 | { 14 | "fieldname": "account_head", 15 | "fieldtype": "Link", 16 | "in_list_view": 1, 17 | "label": "Account Head", 18 | "options": "Account", 19 | "read_only": 1 20 | }, 21 | { 22 | "fieldname": "rate", 23 | "fieldtype": "Percent", 24 | "in_list_view": 1, 25 | "label": "Rate", 26 | "read_only": 1 27 | }, 28 | { 29 | "fieldname": "amount", 30 | "fieldtype": "Currency", 31 | "in_list_view": 1, 32 | "label": "Amount", 33 | "read_only": 1 34 | } 35 | ], 36 | "istable": 1, 37 | "links": [], 38 | "modified": "2020-09-29 03:00:46.321522", 39 | "modified_by": "Administrator", 40 | "module": "POSAwesome", 41 | "name": "POS Closing Shift Taxes", 42 | "owner": "Administrator", 43 | "permissions": [], 44 | "quick_entry": 1, 45 | "sort_field": "modified", 46 | "sort_order": "DESC", 47 | "track_changes": 1 48 | } -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_closing_shift_taxes/pos_closing_shift_taxes.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Youssef Restom 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 POSClosingShiftTaxes(Document): 10 | pass 11 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_coupon/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/posawesome/doctype/pos_coupon/__init__.py -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_coupon/pos_coupon.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021, Youssef Restom and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('POS Coupon', { 5 | setup: function (frm) { 6 | frm.set_query("pos_offer", function () { 7 | return { 8 | filters: { 9 | "company": frm.doc.company, 10 | "coupon_based": 1, 11 | "disable": 0, 12 | } 13 | }; 14 | }); 15 | }, 16 | coupon_name: function (frm) { 17 | if (frm.doc.__islocal === 1) { 18 | frm.trigger("make_coupon_code"); 19 | } 20 | }, 21 | coupon_type: function (frm) { 22 | if (frm.doc.__islocal === 1) { 23 | frm.trigger("make_coupon_code"); 24 | } 25 | }, 26 | make_coupon_code: function (frm) { 27 | var coupon_name = frm.doc.coupon_name; 28 | var coupon_code; 29 | if (frm.doc.coupon_type == 'Gift Card') { 30 | coupon_code = Math.random().toString(12).substring(2, 12).toUpperCase(); 31 | } 32 | else if (frm.doc.coupon_type == 'Promotional') { 33 | coupon_name = coupon_name.replace(/\s/g, ''); 34 | coupon_code = coupon_name.toUpperCase().slice(0, 8); 35 | } 36 | frm.doc.coupon_code = coupon_code; 37 | frm.refresh_field('coupon_code'); 38 | }, 39 | refresh: function (frm) { 40 | if (frm.doc.pricing_rule) { 41 | frm.add_custom_button(__("Add/Edit Coupon Conditions"), function () { 42 | frappe.set_route("Form", "POS Offer", frm.doc.pos_offer); 43 | }); 44 | } 45 | } 46 | }); -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_coupon/pos_coupon.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "allow_import": 1, 4 | "autoname": "field:coupon_name", 5 | "creation": "2021-07-24 01:47:32.743719", 6 | "doctype": "DocType", 7 | "document_type": "Other", 8 | "editable_grid": 1, 9 | "engine": "InnoDB", 10 | "field_order": [ 11 | "coupon_name", 12 | "coupon_type", 13 | "customer", 14 | "customer_name", 15 | "mobile_no", 16 | "email_id", 17 | "column_break_4", 18 | "coupon_code", 19 | "company", 20 | "campaign", 21 | "pos_offer", 22 | "referral_code", 23 | "uses", 24 | "valid_from", 25 | "valid_upto", 26 | "maximum_use", 27 | "used", 28 | "one\u0640use", 29 | "column_break_11", 30 | "description" 31 | ], 32 | "fields": [ 33 | { 34 | "description": "e.g. \"Summer Holiday 2019 Offer 20\"", 35 | "fieldname": "coupon_name", 36 | "fieldtype": "Data", 37 | "label": "Coupon Name", 38 | "reqd": 1, 39 | "unique": 1 40 | }, 41 | { 42 | "fieldname": "coupon_type", 43 | "fieldtype": "Select", 44 | "in_list_view": 1, 45 | "in_standard_filter": 1, 46 | "label": "Coupon Type", 47 | "options": "Promotional\nGift Card", 48 | "reqd": 1 49 | }, 50 | { 51 | "depends_on": "eval: doc.coupon_type == \"Gift Card\"", 52 | "fieldname": "customer", 53 | "fieldtype": "Link", 54 | "in_list_view": 1, 55 | "in_standard_filter": 1, 56 | "label": "Customer", 57 | "options": "Customer" 58 | }, 59 | { 60 | "fieldname": "column_break_4", 61 | "fieldtype": "Column Break" 62 | }, 63 | { 64 | "description": "unique e.g. SAVE20 To be used to get discount", 65 | "fieldname": "coupon_code", 66 | "fieldtype": "Data", 67 | "in_standard_filter": 1, 68 | "label": "Coupon Code", 69 | "no_copy": 1, 70 | "set_only_once": 1, 71 | "unique": 1 72 | }, 73 | { 74 | "fieldname": "pos_offer", 75 | "fieldtype": "Link", 76 | "label": "POS Offer", 77 | "options": "POS Offer", 78 | "reqd": 1 79 | }, 80 | { 81 | "fieldname": "uses", 82 | "fieldtype": "Section Break", 83 | "label": "Validity and Usage" 84 | }, 85 | { 86 | "fieldname": "valid_from", 87 | "fieldtype": "Date", 88 | "in_list_view": 1, 89 | "label": "Valid From" 90 | }, 91 | { 92 | "fieldname": "valid_upto", 93 | "fieldtype": "Date", 94 | "label": "Valid Upto" 95 | }, 96 | { 97 | "depends_on": "eval: doc.coupon_type == \"Promotional\"", 98 | "fieldname": "maximum_use", 99 | "fieldtype": "Int", 100 | "label": "Maximum Use" 101 | }, 102 | { 103 | "default": "0", 104 | "fieldname": "used", 105 | "fieldtype": "Int", 106 | "in_list_view": 1, 107 | "label": "Used", 108 | "no_copy": 1, 109 | "read_only": 1 110 | }, 111 | { 112 | "fieldname": "column_break_11", 113 | "fieldtype": "Column Break" 114 | }, 115 | { 116 | "fetch_from": "pos_offer.description", 117 | "fetch_if_empty": 1, 118 | "fieldname": "description", 119 | "fieldtype": "Text Editor", 120 | "label": "Coupon Description" 121 | }, 122 | { 123 | "fieldname": "company", 124 | "fieldtype": "Link", 125 | "in_standard_filter": 1, 126 | "label": "Company", 127 | "options": "Company", 128 | "reqd": 1 129 | }, 130 | { 131 | "fieldname": "campaign", 132 | "fieldtype": "Link", 133 | "in_standard_filter": 1, 134 | "label": "Campaign", 135 | "options": "Campaign" 136 | }, 137 | { 138 | "default": "0", 139 | "fieldname": "one\u0640use", 140 | "fieldtype": "Check", 141 | "label": "Only One Use Per Customer" 142 | }, 143 | { 144 | "depends_on": "customer", 145 | "fetch_from": "customer.customer_name", 146 | "fieldname": "customer_name", 147 | "fieldtype": "Data", 148 | "label": "Customer Name", 149 | "read_only": 1 150 | }, 151 | { 152 | "depends_on": "customer", 153 | "fetch_from": "customer.mobile_no", 154 | "fetch_if_empty": 1, 155 | "fieldname": "mobile_no", 156 | "fieldtype": "Data", 157 | "label": "Mobile NO", 158 | "options": "Phone" 159 | }, 160 | { 161 | "depends_on": "customer", 162 | "fetch_from": "customer.email_id", 163 | "fetch_if_empty": 1, 164 | "fieldname": "email_id", 165 | "fieldtype": "Data", 166 | "label": "Email ID", 167 | "options": "Email" 168 | }, 169 | { 170 | "fieldname": "referral_code", 171 | "fieldtype": "Link", 172 | "label": "Referral Code", 173 | "options": "Referral Code", 174 | "read_only": 1 175 | } 176 | ], 177 | "index_web_pages_for_search": 1, 178 | "links": [], 179 | "modified": "2021-07-30 00:17:17.711972", 180 | "modified_by": "Administrator", 181 | "module": "POSAwesome", 182 | "name": "POS Coupon", 183 | "owner": "Administrator", 184 | "permissions": [ 185 | { 186 | "create": 1, 187 | "delete": 1, 188 | "email": 1, 189 | "export": 1, 190 | "print": 1, 191 | "read": 1, 192 | "report": 1, 193 | "role": "System Manager", 194 | "share": 1, 195 | "write": 1 196 | }, 197 | { 198 | "create": 1, 199 | "delete": 1, 200 | "email": 1, 201 | "export": 1, 202 | "print": 1, 203 | "read": 1, 204 | "report": 1, 205 | "role": "Accounts User", 206 | "share": 1, 207 | "write": 1 208 | }, 209 | { 210 | "create": 1, 211 | "delete": 1, 212 | "email": 1, 213 | "export": 1, 214 | "print": 1, 215 | "read": 1, 216 | "report": 1, 217 | "role": "Sales Manager", 218 | "share": 1, 219 | "write": 1 220 | }, 221 | { 222 | "create": 1, 223 | "delete": 1, 224 | "email": 1, 225 | "export": 1, 226 | "print": 1, 227 | "read": 1, 228 | "report": 1, 229 | "role": "Website Manager", 230 | "share": 1, 231 | "write": 1 232 | } 233 | ], 234 | "quick_entry": 1, 235 | "sort_field": "modified", 236 | "sort_order": "DESC", 237 | "title_field": "coupon_code", 238 | "track_changes": 1 239 | } -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_coupon/pos_coupon.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Youssef Restom and contributors 2 | # For license information, please see license.txt 3 | 4 | from __future__ import unicode_literals 5 | import frappe 6 | from frappe import _ 7 | from frappe.model.document import Document 8 | from frappe.utils import strip 9 | from frappe.utils import getdate, today 10 | 11 | 12 | class POSCoupon(Document): 13 | def autoname(self): 14 | self.coupon_name = strip(self.coupon_name) 15 | self.name = self.coupon_name 16 | 17 | if not self.coupon_code: 18 | if self.coupon_type == "Promotional": 19 | self.coupon_code = "".join( 20 | i for i in self.coupon_name if not i.isdigit() 21 | )[0:8].upper() 22 | elif self.coupon_type == "Gift Card": 23 | self.coupon_code = frappe.generate_hash()[:10].upper() 24 | 25 | def validate(self): 26 | if self.coupon_type == "Gift Card": 27 | self.maximum_use = 1 28 | if not self.customer: 29 | frappe.throw(_("Please select the customer.")) 30 | pos_offer = frappe.get_doc("POS Offer", self.pos_offer) 31 | if self.company != pos_offer.company: 32 | frappe.throw( 33 | _("Please select the correct POS Offer with the same company.") 34 | ) 35 | if not pos_offer.coupon_based: 36 | frappe.throw(_("Please select Coupon Code Based POS Offer.")) 37 | if pos_offer.disable: 38 | frappe.throw(_("POS Offer is disable.")) 39 | if pos_offer.valid_from and pos_offer.valid_from > getdate(self.valid_from): 40 | self.valid_from = pos_offer.valid_from 41 | if pos_offer.valid_upto and pos_offer.valid_upto < getdate(self.valid_upto): 42 | self.valid_upto = pos_offer.valid_upto 43 | 44 | def create_coupon_from_referral(self): 45 | if not self.customer: 46 | frappe.throw(_("Customer is required")) 47 | if not self.referral_code: 48 | frappe.throw(_("Referral Code is required")) 49 | ref_doc = None 50 | ref_code_exist = frappe.db.exists("Referral Code", self.referral_code) 51 | if not ref_code_exist: 52 | ref_doc = frappe.get_doc( 53 | "Referral Code", {"referral_code": self.referral_code} 54 | ) 55 | else: 56 | ref_doc = frappe.get_doc("Referral Code", self.referral_code) 57 | if not ref_doc: 58 | frappe.throw( 59 | _("Referral Code {0} is not exists").format(self.referral_code) 60 | ) 61 | if ref_doc.disabled: 62 | frappe.throw(_("Referral Code {0} is disabled").format(self.referral_code)) 63 | 64 | self.coupon_name = frappe.generate_hash()[:10].upper() 65 | self.coupon_type = "Gift Card" 66 | self.company = ref_doc.company 67 | self.pos_offer = ref_doc.customer_offer 68 | self.campaign = ref_doc.campaign 69 | self.referral_code = ref_doc.name 70 | self.save(ignore_permissions=True) 71 | 72 | if ref_doc.primary_offer: 73 | doc = frappe.new_doc("POS Coupon") 74 | doc.coupon_name = frappe.generate_hash()[:10].upper() 75 | doc.coupon_type = "Gift Card" 76 | doc.company = ref_doc.company 77 | doc.customer = ref_doc.customer 78 | doc.pos_offer = ref_doc.primary_offer 79 | doc.campaign = ref_doc.campaign 80 | doc.referral_code = ref_doc.name 81 | doc.save(ignore_permissions=True) 82 | 83 | 84 | def check_coupon_code(coupon_code, customer=None, company=None): 85 | res = {"coupon": None} 86 | if not frappe.db.exists("POS Coupon", {"coupon_code": coupon_code.upper()}): 87 | res["msg"] = _("Sorry, this coupon code not exists") 88 | return res 89 | 90 | coupon = frappe.get_doc("POS Coupon", {"coupon_code": coupon_code.upper()}) 91 | pos_offer = frappe.get_doc("POS Offer", coupon.pos_offer) 92 | 93 | if coupon.valid_from: 94 | if coupon.valid_from > getdate(today()): 95 | res["msg"] = _("Sorry, this coupon code's validity has not started") 96 | return res 97 | if coupon.valid_upto: 98 | if coupon.valid_upto < getdate(today()): 99 | res["msg"] = _("Sorry, this coupon code's validity has expired") 100 | return res 101 | if coupon.used and coupon.maximum_use and coupon.used >= coupon.maximum_use: 102 | res["msg"] = _("Sorry, this coupon code is no longer valid") 103 | return res 104 | 105 | if pos_offer.disable: 106 | res["msg"] = _("Sorry, this coupon code is no longer valid") 107 | return res 108 | if pos_offer.valid_from: 109 | if pos_offer.valid_from > getdate(today()): 110 | res["msg"] = _("Sorry, this coupon code's validity has not started") 111 | return res 112 | if pos_offer.valid_upto: 113 | if pos_offer.valid_upto < getdate(today()): 114 | res["msg"] = _("Sorry, this coupon code's validity has expired") 115 | return res 116 | 117 | if customer and coupon.coupon_type == "Gift Card": 118 | if customer != coupon.customer: 119 | res["msg"] = _("Sorry, this coupon code cannot be used by this customer") 120 | return res 121 | 122 | if company and coupon.company != company: 123 | res["msg"] = _("Sorry, this coupon code cannot be used by this company") 124 | return res 125 | 126 | if customer and coupon.oneـuse: 127 | count = frappe.db.count( 128 | "POS Coupon Detail", 129 | filters={ 130 | "parentfield": "posa_coupons", 131 | "parenttype": "Sales Invoice", 132 | "docstatus": 1, 133 | "customer": customer, 134 | }, 135 | ) 136 | if count > 0: 137 | res["msg"] = _("Sorry, {0} have used this coupon before").format(customer) 138 | return res 139 | 140 | res["coupon"] = coupon 141 | res["msg"] = "Apply" 142 | return res 143 | 144 | 145 | def validate_coupon_code(coupon_code, customer=None, company=None): 146 | res = check_coupon_code(coupon_code, customer, company) 147 | if not res.get("coupon"): 148 | frappe.throw(res.get("msg")) 149 | else: 150 | return res 151 | 152 | 153 | def update_coupon_code_count(coupon_name, transaction_type): 154 | coupon = frappe.get_doc("POS Coupon", coupon_name) 155 | if coupon: 156 | if transaction_type == "used": 157 | 158 | if coupon.maximum_use and coupon.used >= coupon.maximum_use: 159 | frappe.throw( 160 | _("{0} Coupon used are {1}. Allowed quantity is exhausted").format( 161 | coupon.coupon_code, coupon.used 162 | ) 163 | ) 164 | else: 165 | coupon.used = coupon.used + 1 166 | coupon.save(ignore_permissions=True) 167 | 168 | elif transaction_type == "cancelled": 169 | if coupon.used > 0: 170 | coupon.used = coupon.used - 1 171 | coupon.save(ignore_permissions=True) 172 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_coupon/test_pos_coupon.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Youssef Restom and Contributors 2 | # See license.txt 3 | 4 | # import frappe 5 | import unittest 6 | 7 | class TestPOSCoupon(unittest.TestCase): 8 | pass 9 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_coupon_detail/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/posawesome/doctype/pos_coupon_detail/__init__.py -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_coupon_detail/pos_coupon_detail.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "creation": "2021-07-25 01:13:04.695345", 4 | "doctype": "DocType", 5 | "editable_grid": 1, 6 | "engine": "InnoDB", 7 | "field_order": [ 8 | "coupon_code", 9 | "coupon", 10 | "type", 11 | "pos_offer", 12 | "applied", 13 | "customer" 14 | ], 15 | "fields": [ 16 | { 17 | "fieldname": "coupon", 18 | "fieldtype": "Link", 19 | "in_list_view": 1, 20 | "label": "Coupon", 21 | "options": "POS Coupon", 22 | "read_only": 1, 23 | "reqd": 1 24 | }, 25 | { 26 | "default": "1", 27 | "fieldname": "applied", 28 | "fieldtype": "Check", 29 | "in_list_view": 1, 30 | "label": "Applied", 31 | "read_only": 1 32 | }, 33 | { 34 | "fetch_from": "coupon.pos_offer", 35 | "fetch_if_empty": 1, 36 | "fieldname": "pos_offer", 37 | "fieldtype": "Link", 38 | "in_list_view": 1, 39 | "label": "POS Offer", 40 | "options": "POS Offer", 41 | "read_only": 1, 42 | "reqd": 1 43 | }, 44 | { 45 | "fetch_from": "coupon.coupon_type", 46 | "fieldname": "type", 47 | "fieldtype": "Data", 48 | "label": "Type", 49 | "read_only": 1 50 | }, 51 | { 52 | "fieldname": "customer", 53 | "fieldtype": "Link", 54 | "label": "Customer", 55 | "options": "Customer", 56 | "read_only": 1 57 | }, 58 | { 59 | "fetch_from": "coupon.coupon_code", 60 | "fetch_if_empty": 1, 61 | "fieldname": "coupon_code", 62 | "fieldtype": "Data", 63 | "in_list_view": 1, 64 | "label": "Coupon Code", 65 | "read_only": 1, 66 | "reqd": 1 67 | } 68 | ], 69 | "index_web_pages_for_search": 1, 70 | "istable": 1, 71 | "links": [], 72 | "modified": "2021-07-25 18:30:50.096464", 73 | "modified_by": "Administrator", 74 | "module": "POSAwesome", 75 | "name": "POS Coupon Detail", 76 | "owner": "Administrator", 77 | "permissions": [], 78 | "quick_entry": 1, 79 | "sort_field": "modified", 80 | "sort_order": "DESC", 81 | "track_changes": 1 82 | } -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_coupon_detail/pos_coupon_detail.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Youssef Restom and contributors 2 | # For license information, please see license.txt 3 | 4 | # import frappe 5 | from frappe.model.document import Document 6 | 7 | class POSCouponDetail(Document): 8 | pass 9 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_offer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/posawesome/doctype/pos_offer/__init__.py -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_offer/pos_offer.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021, Youssef Restom and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('POS Offer', { 5 | setup: function (frm) { 6 | set_filters(frm); 7 | controllers(frm); 8 | }, 9 | refresh: function (frm) { 10 | controllers(frm); 11 | }, 12 | onload: function (frm) { 13 | set_filters(frm); 14 | controllers(frm); 15 | }, 16 | validate: function (frm) { 17 | if (frm.doc.apply_on === 'Transaction') { 18 | if (!frm.doc.min_amt > 0) { 19 | frappe.throw("Min Amount most be more then zero"); 20 | } 21 | } 22 | if (frm.doc.offer === 'Give Product') { 23 | if (!frm.doc.given_qty > 0) { 24 | frappe.throw("Given Quantity most be more then zero"); 25 | } 26 | } 27 | if (frm.doc.offer === 'Loyalty Point') { 28 | if (!frm.doc.loyalty_points > 0) { 29 | frappe.throw("Loyalty Points most be more then zero"); 30 | } 31 | } 32 | if (frm.doc.apply_type === 'Item Group' && frm.doc.offer === 'Give Product' && !frm.doc.replace_item && !frm.doc.replace_cheapest_item) { 33 | frm.set_value('auto', 0); 34 | } 35 | }, 36 | apply_on: function (frm) { 37 | controllers(frm); 38 | }, 39 | offer: function (frm) { 40 | controllers(frm); 41 | }, 42 | apply_type: function (frm) { 43 | controllers(frm); 44 | }, 45 | discount_type: function (frm) { 46 | controllers(frm); 47 | }, 48 | replace_item: function (frm) { 49 | controllers(frm); 50 | }, 51 | replace_cheapest_item: function (frm) { 52 | controllers(frm); 53 | }, 54 | }); 55 | 56 | 57 | const controllers = (frm) => { 58 | frm.toggle_display('item', frm.doc.apply_on === 'Item Code'); 59 | frm.toggle_reqd('item', frm.doc.apply_on === 'Item Code'); 60 | 61 | frm.toggle_display('item_group', frm.doc.apply_on === 'Item Group'); 62 | frm.toggle_reqd('item_group', frm.doc.apply_on === 'Item Group'); 63 | 64 | frm.toggle_display('brand', frm.doc.apply_on === 'Brand'); 65 | frm.toggle_reqd('brand', frm.doc.apply_on === 'Brand'); 66 | 67 | frm.toggle_reqd('min_amt', frm.doc.apply_on === 'Transaction'); 68 | 69 | frm.toggle_display('apply_for_section', frm.doc.offer === 'Give Product'); 70 | frm.toggle_reqd('apply_type', frm.doc.offer === 'Give Product'); 71 | 72 | frm.toggle_display('replace_item', frm.doc.apply_on === 'Item Code' && frm.doc.offer === 'Give Product' && frm.doc.apply_type === 'Item Code'); 73 | frm.toggle_display('replace_cheapest_item', frm.doc.apply_on === 'Item Group' && frm.doc.offer === 'Give Product' && frm.doc.apply_type === 'Item Group'); 74 | 75 | frm.toggle_display('apply_item_code', frm.doc.apply_type === 'Item Code' && !frm.doc.replace_item); 76 | frm.toggle_reqd('apply_item_code', frm.doc.apply_type === 'Item Code' && !frm.doc.replace_item); 77 | 78 | frm.toggle_display('apply_item_group', frm.doc.apply_type === 'Item Group' && !frm.doc.replace_cheapest_item); 79 | frm.toggle_reqd('apply_item_group', frm.doc.apply_type === 'Item Group' && !frm.doc.replace_cheapest_item); 80 | 81 | frm.toggle_display('less_then', frm.doc.apply_type === 'Item Group' && !frm.doc.replace_cheapest_item); 82 | 83 | frm.toggle_display('product_discount_scheme_section', frm.doc.offer === 'Give Product'); 84 | frm.toggle_display('given_qty', frm.doc.offer === 'Give Product'); 85 | frm.toggle_reqd('given_qty', frm.doc.offer === 'Give Product'); 86 | 87 | frm.toggle_display('price_discount_scheme_section', frm.doc.offer !== 'Loyalty Point'); 88 | frm.toggle_display('discount_type', frm.doc.offer !== 'Loyalty Point'); 89 | frm.toggle_reqd('discount_type', frm.doc.offer !== 'Loyalty Point'); 90 | 91 | frm.toggle_display('rate', frm.doc.discount_type === 'Rate'); 92 | frm.toggle_reqd('rate', frm.doc.discount_type === 'Rate'); 93 | 94 | frm.toggle_display('discount_amount', frm.doc.discount_type === 'Discount Amount'); 95 | frm.toggle_reqd('discount_amount', frm.doc.discount_type === 'Discount Amount'); 96 | 97 | frm.toggle_display('discount_percentage', frm.doc.discount_type === 'Discount Percentage'); 98 | frm.toggle_reqd('discount_percentage', frm.doc.discount_type === 'Discount Percentage'); 99 | 100 | frm.toggle_display('loyalty_point_scheme_section', frm.doc.offer === 'Loyalty Point'); 101 | frm.toggle_display('loyalty_program', frm.doc.offer === 'Loyalty Point'); 102 | frm.toggle_reqd('loyalty_program', frm.doc.offer === 'Loyalty Point'); 103 | 104 | frm.toggle_display('loyalty_points', frm.doc.offer === 'Loyalty Point'); 105 | frm.toggle_reqd('loyalty_points', frm.doc.offer === 'Loyalty Point'); 106 | 107 | if (frm.doc.offer === 'Grand Total') { 108 | frm.set_df_property('discount_type', 'options', ['Discount Percentage']); 109 | } else { 110 | frm.set_df_property('discount_type', 'options', ['', 'Rate', 'Discount Percentage', 'Discount Amount']); 111 | } 112 | 113 | if (frm.doc.apply_on === 'Transaction') { 114 | frm.set_df_property('offer', 'options', ['', 'Give Product', 'Grand Total', 'Loyalty Point']); 115 | } else { 116 | frm.set_df_property('offer', 'options', ['', 'Item Price', 'Give Product', 'Grand Total', 'Loyalty Point']); 117 | } 118 | 119 | if (frm.doc.apply_type === 'Item Group' && frm.doc.offer === 'Give Product' && !frm.doc.replace_item && !frm.doc.replace_cheapest_item) { 120 | frm.set_value('auto', 0); 121 | } 122 | if (frm.doc.apply_on !== 'Item Code' || frm.doc.offer !== 'Give Product' || frm.doc.apply_type !== 'Item Code') { 123 | frm.set_value('replace_item', 0); 124 | } 125 | if (frm.doc.apply_on !== 'Item Group' || frm.doc.offer !== 'Give Product' || frm.doc.apply_type !== 'Item Group') { 126 | frm.set_value('replace_cheapest_item', 0); 127 | } 128 | 129 | }; 130 | 131 | const set_filters = (frm) => { 132 | frm.set_query('pos_profile', function () { 133 | return { 134 | filters: { 135 | 'company': frm.doc.company, 136 | } 137 | }; 138 | }); 139 | frm.set_query('warehouse', function () { 140 | return { 141 | filters: { 142 | 'company': frm.doc.company, 143 | 'is_group': 0, 144 | } 145 | }; 146 | }); 147 | frm.set_query('loyalty_program', function () { 148 | return { 149 | filters: { 150 | 'company': frm.doc.company, 151 | } 152 | }; 153 | }); 154 | frm.set_query('item_group', function () { 155 | return { 156 | filters: { 157 | 'is_group': 0, 158 | } 159 | }; 160 | }); 161 | frm.set_query('apply_item_group', function () { 162 | return { 163 | filters: { 164 | 'is_group': 0, 165 | } 166 | }; 167 | }); 168 | }; -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_offer/pos_offer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2021, Youssef Restom 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 POSOffer(Document): 10 | pass 11 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_offer/test_pos_offer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2021, Youssef Restom and Contributors 3 | # See license.txt 4 | from __future__ import unicode_literals 5 | 6 | # import frappe 7 | import unittest 8 | 9 | class TestPOSOffer(unittest.TestCase): 10 | pass 11 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_offer_detail/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/posawesome/doctype/pos_offer_detail/__init__.py -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_offer_detail/pos_offer_detail.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "creation": "2021-06-06 14:55:34.840650", 4 | "doctype": "DocType", 5 | "editable_grid": 1, 6 | "engine": "InnoDB", 7 | "field_order": [ 8 | "offer_name", 9 | "row_id", 10 | "apply_on", 11 | "offer", 12 | "items", 13 | "give_item", 14 | "give_item_row_id", 15 | "offer_applied", 16 | "coupon_based", 17 | "coupon" 18 | ], 19 | "fields": [ 20 | { 21 | "fieldname": "offer_name", 22 | "fieldtype": "Link", 23 | "in_list_view": 1, 24 | "label": "Offer Name", 25 | "options": "POS Offer", 26 | "read_only": 1 27 | }, 28 | { 29 | "fieldname": "apply_on", 30 | "fieldtype": "Data", 31 | "in_list_view": 1, 32 | "label": "Apply On", 33 | "read_only": 1 34 | }, 35 | { 36 | "fieldname": "offer", 37 | "fieldtype": "Data", 38 | "in_list_view": 1, 39 | "label": "Offer", 40 | "read_only": 1 41 | }, 42 | { 43 | "default": "1", 44 | "fieldname": "offer_applied", 45 | "fieldtype": "Check", 46 | "in_list_view": 1, 47 | "label": "Offer Applied", 48 | "read_only": 1 49 | }, 50 | { 51 | "fieldname": "row_id", 52 | "fieldtype": "Data", 53 | "label": "Row ID", 54 | "read_only": 1 55 | }, 56 | { 57 | "fieldname": "items", 58 | "fieldtype": "Small Text", 59 | "label": "Items", 60 | "no_copy": 1, 61 | "print_hide": 1, 62 | "read_only": 1 63 | }, 64 | { 65 | "fieldname": "give_item", 66 | "fieldtype": "Link", 67 | "in_list_view": 1, 68 | "label": "Give Item", 69 | "options": "Item", 70 | "read_only": 1 71 | }, 72 | { 73 | "fieldname": "give_item_row_id", 74 | "fieldtype": "Data", 75 | "label": "Give Item Row ID", 76 | "read_only": 1 77 | }, 78 | { 79 | "fieldname": "coupon", 80 | "fieldtype": "Link", 81 | "in_list_view": 1, 82 | "label": "Coupon", 83 | "options": "POS Coupon", 84 | "read_only": 1 85 | }, 86 | { 87 | "default": "0", 88 | "fetch_from": "offer_name.coupon_based", 89 | "fetch_if_empty": 1, 90 | "fieldname": "coupon_based", 91 | "fieldtype": "Check", 92 | "label": "Coupon Based", 93 | "read_only": 1 94 | } 95 | ], 96 | "index_web_pages_for_search": 1, 97 | "istable": 1, 98 | "links": [], 99 | "modified": "2021-07-25 17:12:41.138596", 100 | "modified_by": "Administrator", 101 | "module": "POSAwesome", 102 | "name": "POS Offer Detail", 103 | "owner": "Administrator", 104 | "permissions": [], 105 | "quick_entry": 1, 106 | "sort_field": "modified", 107 | "sort_order": "DESC", 108 | "track_changes": 1 109 | } -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_offer_detail/pos_offer_detail.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2021, Youssef Restom 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 POSOfferDetail(Document): 10 | pass 11 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_opening_shift/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/posawesome/doctype/pos_opening_shift/__init__.py -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_opening_shift/pos_opening_shift.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Youssef Restom and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('POS Opening Shift', { 5 | setup(frm) { 6 | if (frm.doc.docstatus == 0) { 7 | frm.trigger('set_posting_date_read_only'); 8 | frm.set_value('period_start_date', frappe.datetime.now_datetime()); 9 | frm.set_value('user', frappe.session.user); 10 | } 11 | frm.set_query("user", function(doc) { 12 | return { 13 | query: "posawesome.posawesome.doctype.pos_closing_shift.pos_closing_shift.get_cashiers", 14 | filters: { 'parent': doc.pos_profile } 15 | }; 16 | }); 17 | frm.set_query("pos_profile", function(doc) { 18 | return { 19 | filters: { 'company': doc.company} 20 | }; 21 | }); 22 | }, 23 | 24 | refresh(frm) { 25 | // set default posting date / time 26 | if(frm.doc.docstatus == 0) { 27 | if(!frm.doc.posting_date) { 28 | frm.set_value('posting_date', frappe.datetime.nowdate()); 29 | } 30 | frm.trigger('set_posting_date_read_only'); 31 | } 32 | }, 33 | 34 | set_posting_date_read_only(frm) { 35 | if(frm.doc.docstatus == 0 && frm.doc.set_posting_date) { 36 | frm.set_df_property('posting_date', 'read_only', 0); 37 | } else { 38 | frm.set_df_property('posting_date', 'read_only', 1); 39 | } 40 | }, 41 | 42 | set_posting_date(frm) { 43 | frm.trigger('set_posting_date_read_only'); 44 | }, 45 | 46 | pos_profile: (frm) => { 47 | if (frm.doc.pos_profile) { 48 | frappe.db.get_doc("POS Profile", frm.doc.pos_profile) 49 | .then(({ payments }) => { 50 | if (payments.length) { 51 | frm.doc.balance_details = []; 52 | payments.forEach(({ mode_of_payment }) => { 53 | frm.add_child("balance_details", { mode_of_payment }); 54 | }) 55 | frm.refresh_field("balance_details"); 56 | } 57 | }); 58 | } 59 | } 60 | }); -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_opening_shift/pos_opening_shift.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "autoname": "POSA-OS-.YY.-.#######", 4 | "creation": "2020-09-22 14:15:10.599968", 5 | "doctype": "DocType", 6 | "editable_grid": 1, 7 | "engine": "InnoDB", 8 | "field_order": [ 9 | "period_start_date", 10 | "period_end_date", 11 | "status", 12 | "column_break_3", 13 | "posting_date", 14 | "set_posting_date", 15 | "section_break_5", 16 | "company", 17 | "pos_profile", 18 | "pos_closing_shift", 19 | "column_break_7", 20 | "user", 21 | "opening_balance_details_section", 22 | "balance_details", 23 | "section_break_9", 24 | "amended_from" 25 | ], 26 | "fields": [ 27 | { 28 | "fieldname": "period_start_date", 29 | "fieldtype": "Datetime", 30 | "in_list_view": 1, 31 | "label": "Period Start Date", 32 | "reqd": 1 33 | }, 34 | { 35 | "fieldname": "period_end_date", 36 | "fieldtype": "Date", 37 | "label": "Period End Date", 38 | "read_only": 1 39 | }, 40 | { 41 | "allow_on_submit": 1, 42 | "default": "Draft", 43 | "fieldname": "status", 44 | "fieldtype": "Select", 45 | "hidden": 1, 46 | "label": "Status", 47 | "options": "Draft\nOpen\nClosed\nCancelled", 48 | "read_only": 1 49 | }, 50 | { 51 | "fieldname": "column_break_3", 52 | "fieldtype": "Column Break" 53 | }, 54 | { 55 | "default": "Today", 56 | "fieldname": "posting_date", 57 | "fieldtype": "Date", 58 | "in_list_view": 1, 59 | "label": "Posting Date", 60 | "reqd": 1 61 | }, 62 | { 63 | "default": "0", 64 | "fieldname": "set_posting_date", 65 | "fieldtype": "Check", 66 | "label": "Set Posting Date" 67 | }, 68 | { 69 | "fieldname": "section_break_5", 70 | "fieldtype": "Section Break" 71 | }, 72 | { 73 | "fieldname": "company", 74 | "fieldtype": "Link", 75 | "label": "Company", 76 | "options": "Company", 77 | "reqd": 1 78 | }, 79 | { 80 | "fieldname": "pos_profile", 81 | "fieldtype": "Link", 82 | "in_list_view": 1, 83 | "label": "POS Profile", 84 | "options": "POS Profile", 85 | "reqd": 1 86 | }, 87 | { 88 | "fieldname": "column_break_7", 89 | "fieldtype": "Column Break" 90 | }, 91 | { 92 | "fieldname": "user", 93 | "fieldtype": "Link", 94 | "label": "Cashier", 95 | "options": "User", 96 | "reqd": 1 97 | }, 98 | { 99 | "fieldname": "opening_balance_details_section", 100 | "fieldtype": "Section Break" 101 | }, 102 | { 103 | "fieldname": "balance_details", 104 | "fieldtype": "Table", 105 | "label": "Opening Balance Details", 106 | "options": "POS Opening Shift Detail", 107 | "reqd": 1 108 | }, 109 | { 110 | "fieldname": "section_break_9", 111 | "fieldtype": "Section Break", 112 | "read_only": 1 113 | }, 114 | { 115 | "fieldname": "amended_from", 116 | "fieldtype": "Link", 117 | "label": "Amended From", 118 | "no_copy": 1, 119 | "options": "POS Opening Shift", 120 | "print_hide": 1, 121 | "read_only": 1 122 | }, 123 | { 124 | "allow_on_submit": 1, 125 | "fieldname": "pos_closing_shift", 126 | "fieldtype": "Data", 127 | "label": "POS Closing Shift", 128 | "read_only": 1 129 | } 130 | ], 131 | "is_submittable": 1, 132 | "links": [], 133 | "modified": "2022-11-22 15:04:30.555123", 134 | "modified_by": "Administrator", 135 | "module": "POSAwesome", 136 | "name": "POS Opening Shift", 137 | "owner": "Administrator", 138 | "permissions": [ 139 | { 140 | "cancel": 1, 141 | "create": 1, 142 | "delete": 1, 143 | "email": 1, 144 | "export": 1, 145 | "print": 1, 146 | "read": 1, 147 | "report": 1, 148 | "role": "System Manager", 149 | "share": 1, 150 | "submit": 1, 151 | "write": 1 152 | }, 153 | { 154 | "cancel": 1, 155 | "create": 1, 156 | "email": 1, 157 | "export": 1, 158 | "print": 1, 159 | "read": 1, 160 | "report": 1, 161 | "role": "Sales Manager", 162 | "share": 1, 163 | "submit": 1, 164 | "write": 1 165 | }, 166 | { 167 | "cancel": 1, 168 | "create": 1, 169 | "delete": 1, 170 | "email": 1, 171 | "export": 1, 172 | "print": 1, 173 | "read": 1, 174 | "report": 1, 175 | "role": "Administrator", 176 | "share": 1, 177 | "submit": 1, 178 | "write": 1 179 | } 180 | ], 181 | "sort_field": "modified", 182 | "sort_order": "DESC", 183 | "track_changes": 1 184 | } -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_opening_shift/pos_opening_shift.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Youssef Restom and contributors 3 | # For license information, please see license.txt 4 | 5 | from __future__ import unicode_literals 6 | import frappe 7 | from frappe import _ 8 | from frappe.utils import cint 9 | from frappe.model.document import Document 10 | from posawesome.posawesome.api.status_updater import StatusUpdater 11 | 12 | 13 | class POSOpeningShift(StatusUpdater): 14 | def validate(self): 15 | self.validate_pos_profile_and_cashier() 16 | self.set_status() 17 | 18 | def validate_pos_profile_and_cashier(self): 19 | if self.company != frappe.db.get_value("POS Profile", self.pos_profile, "company"): 20 | frappe.throw(_("POS Profile {} does not belongs to company {}".format(self.pos_profile, self.company))) 21 | 22 | if not cint(frappe.db.get_value("User", self.user, "enabled")): 23 | frappe.throw(_("User {} has been disabled. Please select valid user/cashier".format(self.user))) 24 | 25 | def on_submit(self): 26 | self.set_status(update=True) 27 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_opening_shift/pos_opening_shift_list.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors 2 | // License: GNU General Public License v3. See license.txt 3 | 4 | // render 5 | frappe.listview_settings['POS Opening Shift'] = { 6 | get_indicator: function(doc) { 7 | var status_color = { 8 | "Draft": "grey", 9 | "Open": "orange", 10 | "Closed": "green", 11 | "Cancelled": "red" 12 | 13 | }; 14 | return [__(doc.status), status_color[doc.status], "status,=,"+doc.status]; 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_opening_shift/test_pos_opening_shift.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Youssef Restom and Contributors 3 | # See license.txt 4 | from __future__ import unicode_literals 5 | 6 | # import frappe 7 | import unittest 8 | 9 | class TestPOSOpeningShift(unittest.TestCase): 10 | pass 11 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_opening_shift_detail/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/posawesome/doctype/pos_opening_shift_detail/__init__.py -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_opening_shift_detail/pos_opening_shift_detail.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "creation": "2020-09-22 14:11:51.000467", 4 | "doctype": "DocType", 5 | "editable_grid": 1, 6 | "engine": "InnoDB", 7 | "field_order": [ 8 | "mode_of_payment", 9 | "amount" 10 | ], 11 | "fields": [ 12 | { 13 | "fieldname": "mode_of_payment", 14 | "fieldtype": "Link", 15 | "in_list_view": 1, 16 | "label": "Mode of Payment", 17 | "options": "Mode of Payment", 18 | "reqd": 1 19 | }, 20 | { 21 | "default": "0", 22 | "fieldname": "amount", 23 | "fieldtype": "Currency", 24 | "in_list_view": 1, 25 | "label": "Opening Amount", 26 | "options": "company:company_currency", 27 | "reqd": 1 28 | } 29 | ], 30 | "istable": 1, 31 | "links": [], 32 | "modified": "2020-09-23 02:29:31.193208", 33 | "modified_by": "Administrator", 34 | "module": "POSAwesome", 35 | "name": "POS Opening Shift Detail", 36 | "owner": "Administrator", 37 | "permissions": [], 38 | "quick_entry": 1, 39 | "sort_field": "modified", 40 | "sort_order": "DESC", 41 | "track_changes": 1 42 | } -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_opening_shift_detail/pos_opening_shift_detail.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Youssef Restom 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 POSOpeningShiftDetail(Document): 10 | pass 11 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_payment_entry_reference/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/posawesome/doctype/pos_payment_entry_reference/__init__.py -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_payment_entry_reference/pos_payment_entry_reference.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "creation": "2023-06-12 02:59:56.133380", 4 | "default_view": "List", 5 | "doctype": "DocType", 6 | "editable_grid": 1, 7 | "engine": "InnoDB", 8 | "field_order": [ 9 | "payment_entry", 10 | "posting_date", 11 | "column_break_3", 12 | "customer", 13 | "paid_amount", 14 | "mode_of_payment" 15 | ], 16 | "fields": [ 17 | { 18 | "fieldname": "payment_entry", 19 | "fieldtype": "Link", 20 | "in_list_view": 1, 21 | "label": "Payment Entry", 22 | "options": "Payment Entry", 23 | "reqd": 1 24 | }, 25 | { 26 | "fetch_from": "pos_invoice.posting_date", 27 | "fieldname": "posting_date", 28 | "fieldtype": "Date", 29 | "in_list_view": 1, 30 | "label": "Date", 31 | "reqd": 1 32 | }, 33 | { 34 | "fieldname": "column_break_3", 35 | "fieldtype": "Column Break" 36 | }, 37 | { 38 | "fetch_from": "pos_invoice.customer", 39 | "fieldname": "customer", 40 | "fieldtype": "Link", 41 | "in_list_view": 1, 42 | "label": "Customer", 43 | "options": "Customer", 44 | "read_only": 1, 45 | "reqd": 1 46 | }, 47 | { 48 | "fetch_from": "pos_invoice.grand_total", 49 | "fieldname": "paid_amount", 50 | "fieldtype": "Currency", 51 | "in_list_view": 1, 52 | "label": "Amount", 53 | "reqd": 1 54 | }, 55 | { 56 | "fieldname": "mode_of_payment", 57 | "fieldtype": "Data", 58 | "label": "Mode Of Payment", 59 | "reqd": 1 60 | } 61 | ], 62 | "istable": 1, 63 | "links": [], 64 | "modified": "2023-06-12 02:59:56.133380", 65 | "modified_by": "Administrator", 66 | "module": "POSAwesome", 67 | "name": "POS Payment Entry Reference", 68 | "owner": "Administrator", 69 | "permissions": [], 70 | "quick_entry": 1, 71 | "sort_field": "modified", 72 | "sort_order": "DESC", 73 | "states": [], 74 | "track_changes": 1 75 | } -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/pos_payment_entry_reference/pos_payment_entry_reference.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, Youssef Restom and contributors 2 | # For license information, please see license.txt 3 | 4 | # import frappe 5 | from frappe.model.document import Document 6 | 7 | class POSPaymentEntryReference(Document): 8 | pass 9 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/referral_code/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/posawesome/doctype/referral_code/__init__.py -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/referral_code/referral_code.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021, Youssef Restom and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Referral Code', { 5 | setup: function (frm) { 6 | frm.set_query("party_type", function () { 7 | return { 8 | filters: { 9 | "name": ["in", ["Customer"]], 10 | } 11 | }; 12 | }); 13 | frm.set_query("customer_offer", function () { 14 | return { 15 | filters: { 16 | "company": frm.doc.company, 17 | "coupon_based": 1, 18 | "disable": 0, 19 | } 20 | }; 21 | }); 22 | frm.set_query("primary_offer", function () { 23 | return { 24 | filters: { 25 | "company": frm.doc.company, 26 | "coupon_based": 1, 27 | "disable": 0, 28 | } 29 | }; 30 | }); 31 | }, 32 | referral_name: function (frm) { 33 | if (frm.doc.__islocal === 1) { 34 | frm.trigger("make_referral_code"); 35 | } 36 | }, 37 | make_referral_code: function (frm) { 38 | let referral_name = frm.doc.referral_name; 39 | let referral_code; 40 | if (!referral_name) { 41 | frm.doc.referral_name = frm.doc.party + Math.random().toString(5).substring(2, 5).toUpperCase(); 42 | referral_code = Math.random().toString(12).substring(2, 12).toUpperCase(); 43 | } 44 | else { 45 | referral_name = referral_name.replace(/\s/g, ''); 46 | referral_code = referral_name.toUpperCase().slice(0, 8); 47 | } 48 | frm.doc.referral_code = referral_code; 49 | frm.refresh_field('referral_name'); 50 | frm.refresh_field('referral_code'); 51 | }, 52 | 53 | }); 54 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/referral_code/referral_code.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "autoname": "field:referral_name", 4 | "creation": "2021-07-29 02:49:20.639686", 5 | "doctype": "DocType", 6 | "editable_grid": 1, 7 | "engine": "InnoDB", 8 | "field_order": [ 9 | "disabled", 10 | "section_break_2", 11 | "company", 12 | "customer", 13 | "customer_name", 14 | "mobile_no", 15 | "email_id", 16 | "campaign", 17 | "column_break_5", 18 | "referral_name", 19 | "referral_code", 20 | "customer_offer", 21 | "primary_offer" 22 | ], 23 | "fields": [ 24 | { 25 | "fieldname": "campaign", 26 | "fieldtype": "Link", 27 | "in_list_view": 1, 28 | "in_standard_filter": 1, 29 | "label": "Campaign", 30 | "options": "Campaign" 31 | }, 32 | { 33 | "fieldname": "column_break_5", 34 | "fieldtype": "Column Break" 35 | }, 36 | { 37 | "fieldname": "referral_name", 38 | "fieldtype": "Data", 39 | "label": "Referral Name", 40 | "unique": 1 41 | }, 42 | { 43 | "fieldname": "referral_code", 44 | "fieldtype": "Data", 45 | "label": "Referral Code", 46 | "set_only_once": 1, 47 | "unique": 1 48 | }, 49 | { 50 | "default": "0", 51 | "fieldname": "disabled", 52 | "fieldtype": "Check", 53 | "label": "Disabled" 54 | }, 55 | { 56 | "fieldname": "section_break_2", 57 | "fieldtype": "Section Break" 58 | }, 59 | { 60 | "fieldname": "company", 61 | "fieldtype": "Link", 62 | "label": "Company", 63 | "options": "Company", 64 | "reqd": 1 65 | }, 66 | { 67 | "fieldname": "customer_offer", 68 | "fieldtype": "Link", 69 | "label": "Final Customer Offer", 70 | "options": "POS Offer", 71 | "reqd": 1 72 | }, 73 | { 74 | "fieldname": "primary_offer", 75 | "fieldtype": "Link", 76 | "label": "Primary Customer Offer", 77 | "options": "POS Offer" 78 | }, 79 | { 80 | "fieldname": "customer", 81 | "fieldtype": "Link", 82 | "label": "Customer", 83 | "options": "Customer", 84 | "reqd": 1 85 | }, 86 | { 87 | "fetch_from": "customer.customer_name", 88 | "fieldname": "customer_name", 89 | "fieldtype": "Data", 90 | "label": "Customer Name", 91 | "read_only": 1 92 | }, 93 | { 94 | "fetch_from": "customer.mobile_no", 95 | "fetch_if_empty": 1, 96 | "fieldname": "mobile_no", 97 | "fieldtype": "Data", 98 | "label": "Mobile NO", 99 | "options": "Phone" 100 | }, 101 | { 102 | "fetch_from": "customer.email_id", 103 | "fetch_if_empty": 1, 104 | "fieldname": "email_id", 105 | "fieldtype": "Data", 106 | "label": "Email ID", 107 | "options": "Email" 108 | } 109 | ], 110 | "index_web_pages_for_search": 1, 111 | "links": [], 112 | "modified": "2021-07-29 22:28:54.158213", 113 | "modified_by": "Administrator", 114 | "module": "POSAwesome", 115 | "name": "Referral Code", 116 | "owner": "Administrator", 117 | "permissions": [ 118 | { 119 | "create": 1, 120 | "delete": 1, 121 | "email": 1, 122 | "export": 1, 123 | "print": 1, 124 | "read": 1, 125 | "report": 1, 126 | "role": "System Manager", 127 | "share": 1, 128 | "write": 1 129 | }, 130 | { 131 | "create": 1, 132 | "delete": 1, 133 | "email": 1, 134 | "export": 1, 135 | "print": 1, 136 | "read": 1, 137 | "report": 1, 138 | "role": "Accounts User", 139 | "share": 1, 140 | "write": 1 141 | }, 142 | { 143 | "create": 1, 144 | "delete": 1, 145 | "email": 1, 146 | "export": 1, 147 | "print": 1, 148 | "read": 1, 149 | "report": 1, 150 | "role": "Sales Manager", 151 | "share": 1, 152 | "write": 1 153 | }, 154 | { 155 | "create": 1, 156 | "delete": 1, 157 | "email": 1, 158 | "export": 1, 159 | "print": 1, 160 | "read": 1, 161 | "report": 1, 162 | "role": "Website Manager", 163 | "share": 1, 164 | "write": 1 165 | } 166 | ], 167 | "sort_field": "modified", 168 | "sort_order": "DESC", 169 | "title_field": "referral_code", 170 | "track_changes": 1 171 | } -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/referral_code/referral_code.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Youssef Restom and contributors 2 | # For license information, please see license.txt 3 | 4 | import frappe 5 | from frappe import _ 6 | from frappe.model.document import Document 7 | from frappe.utils import strip 8 | 9 | 10 | class ReferralCode(Document): 11 | def autoname(self): 12 | if not self.referral_name: 13 | self.referral_name = ( 14 | strip(self.customer) + "-" + frappe.generate_hash()[:5].upper() 15 | ) 16 | self.name = self.referral_name 17 | else: 18 | self.referral_name = strip(self.referral_name) 19 | self.name = self.referral_name 20 | 21 | if not self.referral_code: 22 | self.referral_code = frappe.generate_hash()[:10].upper() 23 | 24 | def validate(self): 25 | pass 26 | 27 | 28 | def create_referral_code( 29 | company, customer, customer_offer, primary_offer=None, campaign=None 30 | ): 31 | doc = frappe.new_doc("Referral Code") 32 | doc.company = company 33 | doc.customer = customer 34 | doc.customer_offer = customer_offer 35 | doc.primary_offer = primary_offer 36 | doc.campaign = campaign 37 | doc.save(ignore_permissions=True) 38 | return doc 39 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/referral_code/test_referral_code.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Youssef Restom and Contributors 2 | # See license.txt 3 | 4 | # import frappe 5 | import unittest 6 | 7 | class TestReferralCode(unittest.TestCase): 8 | pass 9 | -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/sales_invoice_reference/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/posawesome/doctype/sales_invoice_reference/__init__.py -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/sales_invoice_reference/sales_invoice_reference.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "creation": "2020-09-29 02:58:12.486831", 4 | "doctype": "DocType", 5 | "editable_grid": 1, 6 | "engine": "InnoDB", 7 | "field_order": [ 8 | "sales_invoice", 9 | "posting_date", 10 | "column_break_3", 11 | "customer", 12 | "grand_total" 13 | ], 14 | "fields": [ 15 | { 16 | "fieldname": "sales_invoice", 17 | "fieldtype": "Link", 18 | "in_list_view": 1, 19 | "label": "Sales Invoice", 20 | "options": "Sales Invoice", 21 | "reqd": 1 22 | }, 23 | { 24 | "fetch_from": "pos_invoice.posting_date", 25 | "fieldname": "posting_date", 26 | "fieldtype": "Date", 27 | "in_list_view": 1, 28 | "label": "Date", 29 | "reqd": 1 30 | }, 31 | { 32 | "fieldname": "column_break_3", 33 | "fieldtype": "Column Break" 34 | }, 35 | { 36 | "fetch_from": "pos_invoice.customer", 37 | "fieldname": "customer", 38 | "fieldtype": "Link", 39 | "in_list_view": 1, 40 | "label": "Customer", 41 | "options": "Customer", 42 | "read_only": 1, 43 | "reqd": 1 44 | }, 45 | { 46 | "fetch_from": "pos_invoice.grand_total", 47 | "fieldname": "grand_total", 48 | "fieldtype": "Currency", 49 | "in_list_view": 1, 50 | "label": "Amount", 51 | "reqd": 1 52 | } 53 | ], 54 | "istable": 1, 55 | "links": [], 56 | "modified": "2023-06-12 02:57:24.861219", 57 | "modified_by": "Administrator", 58 | "module": "POSAwesome", 59 | "name": "Sales Invoice Reference", 60 | "owner": "Administrator", 61 | "permissions": [], 62 | "quick_entry": 1, 63 | "sort_field": "modified", 64 | "sort_order": "DESC", 65 | "states": [], 66 | "track_changes": 1 67 | } -------------------------------------------------------------------------------- /posawesome/posawesome/doctype/sales_invoice_reference/sales_invoice_reference.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2020, Youssef Restom 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 SalesInvoiceReference(Document): 10 | pass 11 | -------------------------------------------------------------------------------- /posawesome/posawesome/page/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/posawesome/page/__init__.py -------------------------------------------------------------------------------- /posawesome/posawesome/page/posapp/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/posawesome/page/posapp/__init__.py -------------------------------------------------------------------------------- /posawesome/posawesome/page/posapp/onscan.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t()):e.onScan=t()}(this,function(){var d={attachTo:function(e,t){if(void 0!==e.scannerDetectionData)throw new Error("onScan.js is already initialized for DOM element "+e);var n={onScan:function(e,t){},onScanError:function(e){},onKeyProcess:function(e,t){},onKeyDetect:function(e,t){},onPaste:function(e,t){},keyCodeMapper:function(e){return d.decodeKeyEvent(e)},onScanButtonLongPress:function(){},scanButtonKeyCode:!1,scanButtonLongPressTime:500,timeBeforeScanTest:100,avgTimeByChar:30,minLength:6,suffixKeyCodes:[9,13],prefixKeyCodes:[],ignoreIfFocusOn:!1,stopPropagation:!1,preventDefault:!1,captureEvents:!1,reactToKeydown:!0,reactToPaste:!1,singleScanQty:1};return t=this._mergeOptions(n,t),e.scannerDetectionData={options:t,vars:{firstCharTime:0,lastCharTime:0,accumulatedString:"",testTimer:!1,longPressTimeStart:0,longPressed:!1}},!0===t.reactToPaste&&e.addEventListener("paste",this._handlePaste,t.captureEvents),!1!==t.scanButtonKeyCode&&e.addEventListener("keyup",this._handleKeyUp,t.captureEvents),!0!==t.reactToKeydown&&!1===t.scanButtonKeyCode||e.addEventListener("keydown",this._handleKeyDown,t.captureEvents),this},detachFrom:function(e){e.scannerDetectionData.options.reactToPaste&&e.removeEventListener("paste",this._handlePaste),!1!==e.scannerDetectionData.options.scanButtonKeyCode&&e.removeEventListener("keyup",this._handleKeyUp),e.removeEventListener("keydown",this._handleKeyDown),e.scannerDetectionData=void 0},getOptions:function(e){return e.scannerDetectionData.options},setOptions:function(e,t){switch(e.scannerDetectionData.options.reactToPaste){case!0:!1===t.reactToPaste&&e.removeEventListener("paste",this._handlePaste);break;case!1:!0===t.reactToPaste&&e.addEventListener("paste",this._handlePaste)}switch(e.scannerDetectionData.options.scanButtonKeyCode){case!1:!1!==t.scanButtonKeyCode&&e.addEventListener("keyup",this._handleKeyUp);break;default:!1===t.scanButtonKeyCode&&e.removeEventListener("keyup",this._handleKeyUp)}return e.scannerDetectionData.options=this._mergeOptions(e.scannerDetectionData.options,t),this._reinitialize(e),this},decodeKeyEvent:function(e){var t=this._getNormalizedKeyNum(e);switch(!0){case 48<=t&&t<=90:case 106<=t&&t<=111:if(void 0!==e.key&&""!==e.key)return e.key;var n=String.fromCharCode(t);switch(e.shiftKey){case!1:n=n.toLowerCase();break;case!0:n=n.toUpperCase()}return n;case 96<=t&&t<=105:return t-96}return""},simulate:function(e,t){return this._reinitialize(e),Array.isArray(t)?t.forEach(function(e){var t={};"object"!=typeof e&&"function"!=typeof e||null===e?t.keyCode=parseInt(e):t=e;var n=new KeyboardEvent("keydown",t);document.dispatchEvent(n)}):this._validateScanCode(e,t),this},_reinitialize:function(e){var t=e.scannerDetectionData.vars;t.firstCharTime=0,t.lastCharTime=0,t.accumulatedString=""},_isFocusOnIgnoredElement:function(e){var t=e.scannerDetectionData.options.ignoreIfFocusOn;if(!t)return!1;var n=document.activeElement;if(Array.isArray(t)){for(var a=0;at.length*i.avgTimeByChar:c={message:"Receieved code was not entered in time"};break;default:return i.onScan.call(e,t,o),n=new CustomEvent("scan",{detail:{scanCode:t,qty:o}}),e.dispatchEvent(n),d._reinitialize(e),!0}return c.scanCode=t,c.scanDuration=s-r,c.avgTimeByChar=i.avgTimeByChar,c.minLength=i.minLength,i.onScanError.call(e,c),n=new CustomEvent("scanError",{detail:c}),e.dispatchEvent(n),d._reinitialize(e),!1},_mergeOptions:function(e,t){var n,a={};for(n in e)Object.prototype.hasOwnProperty.call(e,n)&&(a[n]=e[n]);for(n in t)Object.prototype.hasOwnProperty.call(t,n)&&(a[n]=t[n]);return a},_getNormalizedKeyNum:function(e){return e.which||e.keyCode},_handleKeyDown:function(e){var t=d._getNormalizedKeyNum(e),n=this.scannerDetectionData.options,a=this.scannerDetectionData.vars,i=!1;if(!1!==n.onKeyDetect.call(this,t,e)&&!d._isFocusOnIgnoredElement(this))if(!1===n.scanButtonKeyCode||t!=n.scanButtonKeyCode){switch(!0){case a.firstCharTime&&-1!==n.suffixKeyCodes.indexOf(t):e.preventDefault(),e.stopImmediatePropagation(),i=!0;break;case!a.firstCharTime&&-1!==n.prefixKeyCodes.indexOf(t):e.preventDefault(),e.stopImmediatePropagation(),i=!1;break;default:var o=n.keyCodeMapper.call(this,e);if(null===o)return;a.accumulatedString+=o,n.preventDefault&&e.preventDefault(),n.stopPropagation&&e.stopImmediatePropagation(),i=!1}a.firstCharTime||(a.firstCharTime=Date.now()),a.lastCharTime=Date.now(),a.testTimer&&clearTimeout(a.testTimer),i?(d._validateScanCode(this,a.accumulatedString),a.testTimer=!1):a.testTimer=setTimeout(d._validateScanCode,n.timeBeforeScanTest,this,a.accumulatedString),n.onKeyProcess.call(this,o,e)}else a.longPressed||(a.longPressTimer=setTimeout(n.onScanButtonLongPress,n.scanButtonLongPressTime,this),a.longPressed=!0)},_handlePaste:function(e){if(!d._isFocusOnIgnoredElement(this)){e.preventDefault(),oOptions.stopPropagation&&e.stopImmediatePropagation();var t=(event.clipboardData||window.clipboardData).getData("text");this.scannerDetectionData.options.onPaste.call(this,t,event);var n=this.scannerDetectionData.vars;n.firstCharTime=0,n.lastCharTime=0,d._validateScanCode(this,t)}},_handleKeyUp:function(e){d._isFocusOnIgnoredElement(this)||d._getNormalizedKeyNum(e)==this.scannerDetectionData.options.scanButtonKeyCode&&(clearTimeout(this.scannerDetectionData.vars.longPressTimer),this.scannerDetectionData.vars.longPressed=!1)},isScanInProgressFor:function(e){return 0"); 14 | $("head").append(""); 15 | $("head").append(""); 16 | }; 17 | 18 | //Only if PT as we are not being able to load from pt.csv 19 | if (frappe.boot.lang == "pt") { 20 | $.extend( 21 | frappe._messages, { 22 | "Type": "Tipo", 23 | "is Offer": "é Oferta", 24 | "Total Qty": "Qtd Total", 25 | "Customer": "Cliente", 26 | "Items Group": "Grupo de Itens", 27 | "Search Items": "Procurar Itens", 28 | "Additional Discount": "Desconto Adicional", 29 | "Items Discounts": "Descontos de Itens", 30 | "HOLD": "EM PAUSA", 31 | "Hold": "Em Pausa", 32 | "RETURN": "DEVOLUÇÃO", 33 | "Return": "Devolução", 34 | "CANCEL": "CANCELAR", 35 | "NEW": "NOVO", 36 | "PAY": "PAGAR", 37 | "Order": "Ordem", 38 | "Available QTY": "QTD Disponivel", 39 | "QTY": "QTD", 40 | "Discount Percentage": "Percentagem de Desconto", 41 | "Price list Rate": "Taxa de Lista de Preço", 42 | "Group": "Grupo", 43 | "Stock QTY": "QTD de Stock", 44 | "Stock UOM": "UDM de Stock", 45 | "Card": "Cartão", 46 | "Offers": "Ofertas", 47 | "Applied": "Aplicadas", 48 | "There is no Customer !": "Não tem Cliente !", 49 | "There is no Items !": "Não tem Itens !", 50 | "The existing quantity of item {0} is not enough": "A quantidade existente do item {0} não é suficiente", 51 | "Maximum discount for Item {0} is {1}%": "Desconto Maximo para o Item {0} é {1}%", 52 | "Selected serial numbers of item {0} is incorrect": "Numeros de serie selecionado do item {0} é incorrecto", 53 | "The existing batch quantity of item {0} is not enough": "A quantidade existente do lote para o item {0} não é suficiente", 54 | "The discount should not be higher than {0}%": "O desconto não deve ser maior que {0}%", 55 | "Return Invoice Total Not Correct": "Total da Devolução da Factura não está Correcto", 56 | "Return Invoice Total should not be higher than {0}": "Total da Devolução da Factura não deve maior que {0}", 57 | "The item {0} cannot be returned because it is not in the invoice {1}": "O item {0} não pode ser devolvido porque não está na factura {1}", 58 | "The QTY of the item {0} cannot be greater than {1}": "A QTD do item {0} não pode ser maior que {1}", 59 | "Selected Serial No QTY is {0} it should be {1}": "A QTD selecionada do Num. de Serie é {0} deveria ser {1}", 60 | "Loyalty Point Offer Applied": "Oferta de Pontos de Lealdade Aplicada", 61 | "Loyalty Points": "Pontos de Lealdade", 62 | "Paid Amount": "Valor Pago", 63 | "To Be Paid": "A ser Pago", 64 | "Cash": "Numerário", 65 | "Tax and Charges": "Taxas e Impostos", 66 | "Discount Amount": "Valor de Desconto", 67 | "Total Amount": "Valor Total", 68 | "Totoal Amount": "Valor Total", 69 | "Grand Amount": "Total Geral", 70 | "Back": "Voltar", 71 | "Submit Payments": "Submeter Pagamentos", 72 | "Give Item": "Entregar Item", 73 | "New Offer Available": "Nova Oferta Disponivel", 74 | "POS Offers": "Ofertas POS", 75 | "Customer contact created successfully.": "Contacto de Cliente criado com sucesso.", 76 | "Customer Address created successfully.": "Endereço de Cliente criado com sucesso.", 77 | "Customer contact updated successfully.": "Contacto de Cliente actualizacdo com sucesso.", 78 | "Offer": "Oferta", 79 | "Apply On": "Aplicar Em", 80 | "Offer Applied": "Oferta Aplicada", 81 | "Opening Amount": "Valor de Abertura", 82 | "Closing Amount": "Valor de Fecho", 83 | "Expected Amount": "Valor Esperado", 84 | "Difference": "Diferença", 85 | "Close": "Fechar", 86 | "Submit": "Submeter", 87 | "Closing POS Shift": "Fechando Turno do POS", 88 | "Select Hold Invoice": "Selecionar Factura em Pausa", 89 | "Customer Info": "Info do Cliente", 90 | "Add New Address": "Adicionar Novo Endereço", 91 | "New Customer": "Novo Cliente", 92 | "Create POS Opening Shift": "Criar Turno de Abertura POS", 93 | "Select Return Invoice": "Selecione a Factura para Devolução", 94 | "Close Shift": "Fechar Turno", 95 | "Pages": "Paginas", 96 | "Customer not found": "Cliente não encontrado", 97 | "Customer Name": "Nome do Cliente", 98 | "Batch No Available QTY": "QTD Disponivel para o Lote", 99 | "Batch No Expiry Date": "Data de Expiração do Lote", 100 | "Batch No": "Num. do Lote", 101 | "Use Customer Credit": "Usar Crédito Cliente", 102 | "Is Credit Sale": "É Venda a Crédito", 103 | "Due Date": "Data de Expiração", 104 | }); 105 | } -------------------------------------------------------------------------------- /posawesome/posawesome/page/posapp/posapp.json: -------------------------------------------------------------------------------- 1 | { 2 | "content": null, 3 | "creation": "2020-09-13 03:04:25.020107", 4 | "docstatus": 0, 5 | "doctype": "Page", 6 | "idx": 0, 7 | "modified": "2020-09-23 14:53:30.009891", 8 | "modified_by": "Administrator", 9 | "module": "POSAwesome", 10 | "name": "posapp", 11 | "owner": "Administrator", 12 | "page_name": "posapp", 13 | "roles": [ 14 | { 15 | "role": "Sales User" 16 | }, 17 | { 18 | "role": "Sales Manager" 19 | }, 20 | { 21 | "role": "System Manager" 22 | }, 23 | { 24 | "role": "Accounts Manager" 25 | }, 26 | { 27 | "role": "Accounts User" 28 | } 29 | ], 30 | "script": null, 31 | "standard": "Yes", 32 | "style": null, 33 | "system_page": 0, 34 | "title": "POS Awesome" 35 | } -------------------------------------------------------------------------------- /posawesome/posawesome/workspace/pos_awesome/pos_awesome.json: -------------------------------------------------------------------------------- 1 | { 2 | "charts": [], 3 | "content": "[{\"id\":\"cJigdSD9mh\",\"type\":\"header\",\"data\":{\"text\":\"POS Awesome\",\"col\":12}},{\"id\":\"4D2sc3CbN3\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"POS Awesome App\",\"col\":3}},{\"id\":\"nVBkn7nfDw\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"-B_qEZqEA6\",\"type\":\"card\",\"data\":{\"card_name\":\"POS\",\"col\":4}},{\"id\":\"tsAHaUCd5l\",\"type\":\"card\",\"data\":{\"card_name\":\"Profile\",\"col\":4}},{\"id\":\"2-3HMkGou3\",\"type\":\"card\",\"data\":{\"card_name\":\"Shift\",\"col\":4}},{\"id\":\"GdPtnrazDS\",\"type\":\"card\",\"data\":{\"card_name\":\"Delivery Charges\",\"col\":4}},{\"id\":\"cABO53xhGv\",\"type\":\"card\",\"data\":{\"card_name\":\"Offers & Coupons\",\"col\":4}}]", 4 | "creation": "2022-11-29 14:33:45.038200", 5 | "custom_blocks": [], 6 | "docstatus": 0, 7 | "doctype": "Workspace", 8 | "for_user": "", 9 | "hide_custom": 0, 10 | "icon": "retail", 11 | "idx": 0, 12 | "is_hidden": 0, 13 | "label": "POS Awesome", 14 | "links": [ 15 | { 16 | "hidden": 0, 17 | "is_query_report": 0, 18 | "label": "POS Awesome", 19 | "link_count": 0, 20 | "link_to": "posapp", 21 | "link_type": "Page", 22 | "onboard": 0, 23 | "type": "Link" 24 | }, 25 | { 26 | "hidden": 0, 27 | "is_query_report": 0, 28 | "label": "Profile", 29 | "link_count": 1, 30 | "onboard": 0, 31 | "type": "Card Break" 32 | }, 33 | { 34 | "hidden": 0, 35 | "is_query_report": 0, 36 | "label": "POS Profile", 37 | "link_count": 0, 38 | "link_to": "POS Profile", 39 | "link_type": "DocType", 40 | "onboard": 0, 41 | "type": "Link" 42 | }, 43 | { 44 | "hidden": 0, 45 | "is_query_report": 0, 46 | "label": "Delivery Charges", 47 | "link_count": 1, 48 | "onboard": 0, 49 | "type": "Card Break" 50 | }, 51 | { 52 | "hidden": 0, 53 | "is_query_report": 0, 54 | "label": "Delivery Charges", 55 | "link_count": 0, 56 | "link_to": "Delivery Charges", 57 | "link_type": "DocType", 58 | "onboard": 0, 59 | "type": "Link" 60 | }, 61 | { 62 | "hidden": 0, 63 | "is_query_report": 0, 64 | "label": "Offers & Coupons", 65 | "link_count": 3, 66 | "onboard": 0, 67 | "type": "Card Break" 68 | }, 69 | { 70 | "hidden": 0, 71 | "is_query_report": 0, 72 | "label": "Offers", 73 | "link_count": 0, 74 | "link_to": "POS Offer", 75 | "link_type": "DocType", 76 | "onboard": 0, 77 | "type": "Link" 78 | }, 79 | { 80 | "hidden": 0, 81 | "is_query_report": 0, 82 | "label": "Coupons", 83 | "link_count": 0, 84 | "link_to": "POS Coupon", 85 | "link_type": "DocType", 86 | "onboard": 0, 87 | "type": "Link" 88 | }, 89 | { 90 | "hidden": 0, 91 | "is_query_report": 0, 92 | "label": "Referral Code", 93 | "link_count": 0, 94 | "link_to": "Referral Code", 95 | "link_type": "DocType", 96 | "onboard": 0, 97 | "type": "Link" 98 | }, 99 | { 100 | "hidden": 0, 101 | "is_query_report": 0, 102 | "label": "POS", 103 | "link_count": 1, 104 | "onboard": 0, 105 | "type": "Card Break" 106 | }, 107 | { 108 | "hidden": 0, 109 | "is_query_report": 0, 110 | "label": "POS Awesome App", 111 | "link_count": 0, 112 | "link_to": "posapp", 113 | "link_type": "Page", 114 | "onboard": 0, 115 | "type": "Link" 116 | }, 117 | { 118 | "hidden": 0, 119 | "is_query_report": 0, 120 | "label": "Shift", 121 | "link_count": 2, 122 | "onboard": 0, 123 | "type": "Card Break" 124 | }, 125 | { 126 | "hidden": 0, 127 | "is_query_report": 0, 128 | "label": "Opening Shift", 129 | "link_count": 0, 130 | "link_to": "POS Opening Shift", 131 | "link_type": "DocType", 132 | "onboard": 0, 133 | "type": "Link" 134 | }, 135 | { 136 | "hidden": 0, 137 | "is_query_report": 0, 138 | "label": "Closing Shift", 139 | "link_count": 0, 140 | "link_to": "POS Closing Shift", 141 | "link_type": "DocType", 142 | "onboard": 0, 143 | "type": "Link" 144 | } 145 | ], 146 | "modified": "2023-06-07 17:35:14.887611", 147 | "modified_by": "Administrator", 148 | "module": "POSAwesome", 149 | "name": "POS Awesome", 150 | "number_cards": [], 151 | "owner": "Administrator", 152 | "parent_page": "", 153 | "public": 1, 154 | "quick_lists": [], 155 | "roles": [], 156 | "sequence_id": 1.0, 157 | "shortcuts": [ 158 | { 159 | "color": "Grey", 160 | "doc_view": "List", 161 | "label": "POS Awesome App", 162 | "link_to": "posapp", 163 | "type": "Page" 164 | } 165 | ], 166 | "title": "POS Awesome" 167 | } -------------------------------------------------------------------------------- /posawesome/public/js/posapp/Home.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 48 | 49 | 54 | -------------------------------------------------------------------------------- /posawesome/public/js/posapp/bus.js: -------------------------------------------------------------------------------- 1 | export const evntBus = new Vue(); -------------------------------------------------------------------------------- /posawesome/public/js/posapp/components/pos/ClosingDialog.vue: -------------------------------------------------------------------------------- 1 | 76 | 77 | 147 | -------------------------------------------------------------------------------- /posawesome/public/js/posapp/components/pos/Customer.vue: -------------------------------------------------------------------------------- 1 | 60 | 61 | 169 | -------------------------------------------------------------------------------- /posawesome/public/js/posapp/components/pos/Drafts.vue: -------------------------------------------------------------------------------- 1 | 49 | 50 | 115 | -------------------------------------------------------------------------------- /posawesome/public/js/posapp/components/pos/Mpesa-Payments.vue: -------------------------------------------------------------------------------- 1 | 72 | 73 | 183 | -------------------------------------------------------------------------------- /posawesome/public/js/posapp/components/pos/NewAddress.vue: -------------------------------------------------------------------------------- 1 | 78 | 79 | 125 | -------------------------------------------------------------------------------- /posawesome/public/js/posapp/components/pos/OpeningDialog.vue: -------------------------------------------------------------------------------- 1 | 79 | 80 | 201 | -------------------------------------------------------------------------------- /posawesome/public/js/posapp/components/pos/Pos.vue: -------------------------------------------------------------------------------- 1 | 63 | 64 | 234 | 235 | 236 | -------------------------------------------------------------------------------- /posawesome/public/js/posapp/components/pos/Returns.vue: -------------------------------------------------------------------------------- 1 | 67 | 68 | 166 | -------------------------------------------------------------------------------- /posawesome/public/js/posapp/components/pos/SalesOrders.vue: -------------------------------------------------------------------------------- 1 | 75 | 76 | 224 | -------------------------------------------------------------------------------- /posawesome/public/js/posapp/components/pos/Variants.vue: -------------------------------------------------------------------------------- 1 | 73 | 74 | 156 | -------------------------------------------------------------------------------- /posawesome/public/js/posapp/components/pos/placeholder-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/public/js/posapp/components/pos/placeholder-image.png -------------------------------------------------------------------------------- /posawesome/public/js/posapp/components/pos/pos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/public/js/posapp/components/pos/pos.png -------------------------------------------------------------------------------- /posawesome/public/js/posapp/format.js: -------------------------------------------------------------------------------- 1 | export default { 2 | data () { 3 | return { 4 | float_precision: 2, 5 | currency_precision: 2 6 | }; 7 | }, 8 | methods: { 9 | flt (value, precision, number_format, rounding_method) { 10 | if (!precision && precision != 0) { 11 | precision = this.currency_precision || 2; 12 | } 13 | if (!rounding_method) { 14 | rounding_method = "Banker's Rounding (legacy)"; 15 | } 16 | return flt(value, precision, number_format, rounding_method); 17 | }, 18 | formtCurrency (value, precision) { 19 | const format = get_number_format(this.pos_profile?.currency); 20 | value = format_number( 21 | value, 22 | format, 23 | precision || this.currency_precision || 2 24 | ); 25 | return value; 26 | }, 27 | formtFloat (value, precision) { 28 | const format = get_number_format(this.pos_profile.currency); 29 | value = format_number(value, format, precision || this.float_precision || 2); 30 | return value; 31 | }, 32 | setFormatedCurrency (el, field_name, precision, no_negative = false, $event) { 33 | let value = 0; 34 | try { 35 | // make sure it is a number and positive 36 | let _value = parseFloat($event); 37 | if (!isNaN(_value)) { 38 | value = _value; 39 | } 40 | if (no_negative && value < 0) { 41 | value = value * -1; 42 | } 43 | value = this.formtCurrency($event, precision); 44 | } catch (e) { 45 | console.error(e); 46 | value = 0; 47 | } 48 | // check if el is an object 49 | if (typeof el === "object") { 50 | el[field_name] = value; 51 | } 52 | else { 53 | this[field_name] = value; 54 | } 55 | 56 | 57 | return value; 58 | }, 59 | setFormatedFloat (el, field_name, precision, no_negative = false, $event) { 60 | let value = 0; 61 | try { 62 | // make sure it is a number and positive 63 | value = parseFloat($event); 64 | if (isNaN(value)) { 65 | value = 0; 66 | } else if (no_negative && value < 0) { 67 | value = value * -1; 68 | } 69 | value = this.formtFloat($event, precision); 70 | } catch (e) { 71 | console.error(e); 72 | value = 0; 73 | } 74 | // check if el is an object 75 | if (typeof el === "object") { 76 | el[field_name] = value; 77 | } 78 | else { 79 | this[field_name] = value; 80 | } 81 | return value; 82 | }, 83 | currencySymbol (currency) { 84 | return get_currency_symbol(currency); 85 | }, 86 | isNumber (value) { 87 | const pattern = /^-?(\d+|\d{1,3}(\.\d{3})*)(,\d+)?$/; 88 | return pattern.test(value) || "invalid number"; 89 | 90 | } 91 | }, 92 | mounted () { 93 | this.float_precision = 94 | frappe.defaults.get_default('float_precision') || 2; 95 | this.currency_precision = 96 | frappe.defaults.get_default('currency_precision') || 2; 97 | } 98 | }; -------------------------------------------------------------------------------- /posawesome/public/js/posapp/posapp.js: -------------------------------------------------------------------------------- 1 | import Home from './Home.vue'; 2 | 3 | frappe.provide('frappe.PosApp'); 4 | 5 | 6 | frappe.PosApp.posapp = class { 7 | constructor({ parent }) { 8 | this.$parent = $(document); 9 | this.page = parent.page; 10 | this.make_body(); 11 | 12 | } 13 | make_body () { 14 | this.$el = this.$parent.find('.main-section'); 15 | this.vue = new Vue({ 16 | vuetify: new Vuetify( 17 | { 18 | rtl: frappe.utils.is_rtl(), 19 | theme: { 20 | themes: { 21 | light: { 22 | background: '#FFFFFF', 23 | primary: '#0097A7', 24 | secondary: '#00BCD4', 25 | accent: '#9575CD', 26 | success: '#66BB6A', 27 | info: '#2196F3', 28 | warning: '#FF9800', 29 | error: '#E86674', 30 | orange: '#E65100', 31 | golden: '#A68C59', 32 | badge: '#F5528C', 33 | customPrimary: '#085294', 34 | }, 35 | }, 36 | }, 37 | } 38 | ), 39 | el: this.$el[0], 40 | data: { 41 | }, 42 | render: h => h(Home), 43 | }); 44 | } 45 | setup_header () { 46 | 47 | } 48 | 49 | }; 50 | -------------------------------------------------------------------------------- /posawesome/public/js/posawesome.bundle.js: -------------------------------------------------------------------------------- 1 | import './toConsole'; 2 | import './posapp/posapp'; -------------------------------------------------------------------------------- /posawesome/public/js/toConsole.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | frappe.realtime.on('toconsole', function(data) { 3 | data.forEach(element => { 4 | console.log(element); 5 | }); 6 | }); 7 | }); -------------------------------------------------------------------------------- /posawesome/templates/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/templates/__init__.py -------------------------------------------------------------------------------- /posawesome/templates/pages/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/templates/pages/__init__.py -------------------------------------------------------------------------------- /posawesome/templates/pages/__pycache__/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/posawesome/templates/pages/__pycache__/__init__.py -------------------------------------------------------------------------------- /posawesome/uninstall.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def after_uninstall(): 5 | clear_custom_fields_and_properties() 6 | 7 | 8 | def clear_custom_fields_and_properties(): 9 | fixtures = frappe.get_hooks("fixtures", app_name="posawesome") 10 | for fixture in fixtures: 11 | if fixture.get("doctype") == "Custom Field": 12 | filters = fixture.get("filters") 13 | if filters: 14 | for filter in filters: 15 | frappe.db.delete("Custom Field", filter) 16 | print("Deleted Custom Fields: ", filter) 17 | if fixture.get("doctype") == "Property Setter": 18 | filters = fixture.get("filters") 19 | if filters: 20 | for filter in filters: 21 | frappe.db.delete("Property Setter", filter) 22 | print("Deleted Property Setter: ", filter) 23 | 24 | frappe.db.commit() 25 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # frappe # https://github.com/frappe/frappe is installed during bench-init 2 | # erpnext # https://github.com/frappe/erpnext it should be installed manually 3 | -------------------------------------------------------------------------------- /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 posawesome/__init__.py 8 | from posawesome import __version__ as version 9 | 10 | setup( 11 | name="posawesome", 12 | version=version, 13 | description="POS Awesome", 14 | author="Yousef Restom", 15 | author_email="youssef@totrox.com", 16 | packages=find_packages(), 17 | zip_safe=False, 18 | include_package_data=True, 19 | install_requires=install_requires, 20 | ) 21 | -------------------------------------------------------------------------------- /wiki_images/CONFIG AND FILTERS.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/CONFIG AND FILTERS.PNG -------------------------------------------------------------------------------- /wiki_images/CONFIGIRATION.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/CONFIGIRATION.PNG -------------------------------------------------------------------------------- /wiki_images/Customer icon.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/Customer icon.PNG -------------------------------------------------------------------------------- /wiki_images/PAYMENT METHODS.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/PAYMENT METHODS.PNG -------------------------------------------------------------------------------- /wiki_images/PROMOS.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/PROMOS.PNG -------------------------------------------------------------------------------- /wiki_images/QUANTITYCONDITIONS.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/QUANTITYCONDITIONS.PNG -------------------------------------------------------------------------------- /wiki_images/auto set.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/auto set.PNG -------------------------------------------------------------------------------- /wiki_images/batch price.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/batch price.PNG -------------------------------------------------------------------------------- /wiki_images/batch pricing show.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/batch pricing show.PNG -------------------------------------------------------------------------------- /wiki_images/batch.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/batch.PNG -------------------------------------------------------------------------------- /wiki_images/cake.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/cake.PNG -------------------------------------------------------------------------------- /wiki_images/cakes 2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/cakes 2.PNG -------------------------------------------------------------------------------- /wiki_images/changeview.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/changeview.PNG -------------------------------------------------------------------------------- /wiki_images/closing popup.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/closing popup.PNG -------------------------------------------------------------------------------- /wiki_images/credit sale.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/credit sale.PNG -------------------------------------------------------------------------------- /wiki_images/cust4loyalty.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/cust4loyalty.PNG -------------------------------------------------------------------------------- /wiki_images/customer credit.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/customer credit.PNG -------------------------------------------------------------------------------- /wiki_images/customer search.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/customer search.PNG -------------------------------------------------------------------------------- /wiki_images/delivery 2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/delivery 2.PNG -------------------------------------------------------------------------------- /wiki_images/delivery date.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/delivery date.PNG -------------------------------------------------------------------------------- /wiki_images/endofshift.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/endofshift.PNG -------------------------------------------------------------------------------- /wiki_images/hiddenshift.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/hiddenshift.PNG -------------------------------------------------------------------------------- /wiki_images/hide shift.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/hide shift.PNG -------------------------------------------------------------------------------- /wiki_images/inside pos offers.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/inside pos offers.PNG -------------------------------------------------------------------------------- /wiki_images/item details.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/item details.PNG -------------------------------------------------------------------------------- /wiki_images/label.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/label.PNG -------------------------------------------------------------------------------- /wiki_images/listview.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/listview.PNG -------------------------------------------------------------------------------- /wiki_images/loyalty view.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/loyalty view.PNG -------------------------------------------------------------------------------- /wiki_images/new advanced awesome settings.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/new advanced awesome settings.PNG -------------------------------------------------------------------------------- /wiki_images/opening.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/opening.png -------------------------------------------------------------------------------- /wiki_images/options2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/options2.png -------------------------------------------------------------------------------- /wiki_images/payment cart.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/payment cart.PNG -------------------------------------------------------------------------------- /wiki_images/payment.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/payment.PNG -------------------------------------------------------------------------------- /wiki_images/popup.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/popup.PNG -------------------------------------------------------------------------------- /wiki_images/pos 1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/pos 1.PNG -------------------------------------------------------------------------------- /wiki_images/pos closing 3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/pos closing 3.PNG -------------------------------------------------------------------------------- /wiki_images/posclosing1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/posclosing1.PNG -------------------------------------------------------------------------------- /wiki_images/posclosing2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/posclosing2.PNG -------------------------------------------------------------------------------- /wiki_images/profile1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/profile1.PNG -------------------------------------------------------------------------------- /wiki_images/profile2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/profile2.PNG -------------------------------------------------------------------------------- /wiki_images/promo type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/promo type.png -------------------------------------------------------------------------------- /wiki_images/qualifying section.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/qualifying section.PNG -------------------------------------------------------------------------------- /wiki_images/qualigying options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/qualigying options.png -------------------------------------------------------------------------------- /wiki_images/readme.md: -------------------------------------------------------------------------------- 1 | This Folder contains images for the Wiki 2 | -------------------------------------------------------------------------------- /wiki_images/redeem.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/redeem.PNG -------------------------------------------------------------------------------- /wiki_images/replace.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/replace.PNG -------------------------------------------------------------------------------- /wiki_images/return button.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/return button.PNG -------------------------------------------------------------------------------- /wiki_images/return cart.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/return cart.PNG -------------------------------------------------------------------------------- /wiki_images/return search.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/return search.PNG -------------------------------------------------------------------------------- /wiki_images/rewatrd.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/rewatrd.PNG -------------------------------------------------------------------------------- /wiki_images/sales order.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/sales order.PNG -------------------------------------------------------------------------------- /wiki_images/scale.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/scale.PNG -------------------------------------------------------------------------------- /wiki_images/search.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/search.PNG -------------------------------------------------------------------------------- /wiki_images/serial numbers.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/serial numbers.PNG -------------------------------------------------------------------------------- /wiki_images/shiftdiff.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/shiftdiff.PNG -------------------------------------------------------------------------------- /wiki_images/starting.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/starting.PNG -------------------------------------------------------------------------------- /wiki_images/users.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ucraft-com/POS-Awesome/a86fd291ab18a655b3f6d58882b01ecad81fe6af/wiki_images/users.PNG -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | lodash@^4.17.21: 6 | version "4.17.21" 7 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" 8 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 9 | 10 | vuetify@^2.6.10: 11 | version "2.6.10" 12 | resolved "https://registry.yarnpkg.com/vuetify/-/vuetify-2.6.10.tgz#b86cd7a97bf8cd3828a72c349795b5b3c539ebc2" 13 | integrity sha512-fgUeRDDCwYkwu6WGEEKGe7IdfzOsXJCZGrqkn1pcS2ycuoDL8mR2/dejH5iFNnBY6MnsT365PAGn0J+9otjfQg== 14 | --------------------------------------------------------------------------------