From 11a0252f574138b2522f56e91bfd906c35111fe2 Mon Sep 17 00:00:00 2001 From: Yousef Date: Wed, 7 Jun 2023 16:39:15 +0200 Subject: [PATCH 01/12] fix: POS Closing Shift difference amount #323 --- .../pos_closing_shift/pos_closing_shift.py | 163 ++++++++++++------ .../workspace/pos_awesome/pos_awesome.json | 63 +++---- 2 files changed, 139 insertions(+), 87 deletions(-) diff --git a/posawesome/posawesome/doctype/pos_closing_shift/pos_closing_shift.py b/posawesome/posawesome/doctype/pos_closing_shift/pos_closing_shift.py index 06d2fb59..ef1a3869 100644 --- a/posawesome/posawesome/doctype/pos_closing_shift/pos_closing_shift.py +++ b/posawesome/posawesome/doctype/pos_closing_shift/pos_closing_shift.py @@ -12,34 +12,49 @@ class POSClosingShift(Document): def validate(self): - user = frappe.get_all('POS Closing Shift', + user = frappe.get_all( + "POS Closing Shift", filters={ - 'user': self.user, - 'docstatus': 1, + "user": self.user, + "docstatus": 1, "pos_opening_shift": self.pos_opening_shift, - "name": ["!=", self.name] - } + "name": ["!=", self.name], + }, ) if user: - frappe.throw(_("POS Closing Shift {} against {} between selected period" - .format(frappe.bold("already exists"), frappe.bold(self.user))), title=_("Invalid Period")) - - if frappe.db.get_value("POS Opening Shift", self.pos_opening_shift, "status") != "Open": - frappe.throw(_("Selected POS Opening Shift should be open."), title=_( - "Invalid Opening Entry")) + frappe.throw( + _( + "POS Closing Shift {} against {} between selected period".format( + frappe.bold("already exists"), frappe.bold(self.user) + ) + ), + title=_("Invalid Period"), + ) + + if ( + frappe.db.get_value("POS Opening Shift", self.pos_opening_shift, "status") + != "Open" + ): + frappe.throw( + _("Selected POS Opening Shift should be open."), + title=_("Invalid Opening Entry"), + ) self.update_payment_reconciliation() - + def update_payment_reconciliation(self): # update the difference values in Payment Reconciliation child table # get default precision for site - precision = frappe.get_cached_value('System Settings', None, 'currency_precision') or 3 + precision = ( + frappe.get_cached_value("System Settings", None, "currency_precision") or 3 + ) for d in self.payment_reconciliation: - d.difference = flt(d.opening_amount, precision) + flt(d.closing_amount, precision) - flt(d.expected_amount, precision) + d.difference = +flt(d.closing_amount, precision) - flt( + d.expected_amount, precision + ) def on_submit(self): - opening_entry = frappe.get_doc( - "POS Opening Shift", self.pos_opening_shift) + opening_entry = frappe.get_doc("POS Opening Shift", self.pos_opening_shift) opening_entry.pos_closing_shift = self.name opening_entry.set_status() self.delete_draft_invoices() @@ -47,43 +62,51 @@ def on_submit(self): def delete_draft_invoices(self): if frappe.get_value("POS Profile", self.pos_profile, "posa_allow_delete"): - data = frappe.db.sql(""" + data = frappe.db.sql( + """ select name from `tabSales Invoice` where docstatus = 0 and posa_is_printed = 0 and posa_pos_opening_shift = %s - """, (self.pos_opening_shift), as_dict=1) + """, + (self.pos_opening_shift), + as_dict=1, + ) for invoice in data: frappe.delete_doc("Sales Invoice", invoice.name, force=1) def get_payment_reconciliation_details(self): - currency = frappe.get_cached_value( - 'Company', self.company, "default_currency") - return frappe.render_template("posawesome/posawesome/doctype/pos_closing_shift/closing_shift_details.html", - {"data": self, "currency": currency}) + currency = frappe.get_cached_value("Company", self.company, "default_currency") + return frappe.render_template( + "posawesome/posawesome/doctype/pos_closing_shift/closing_shift_details.html", + {"data": self, "currency": currency}, + ) @frappe.whitelist() def get_cashiers(doctype, txt, searchfield, start, page_len, filters): - cashiers_list = frappe.get_all( - "POS Profile User", filters=filters, fields=['user']) - return [c['user'] for c in cashiers_list] + cashiers_list = frappe.get_all("POS Profile User", filters=filters, fields=["user"]) + return [c["user"] for c in cashiers_list] @frappe.whitelist() def get_pos_invoices(pos_opening_shift): submit_printed_invoices(pos_opening_shift) - data = frappe.db.sql(""" + data = frappe.db.sql( + """ select name from `tabSales Invoice` where docstatus = 1 and posa_pos_opening_shift = %s - """, (pos_opening_shift), as_dict=1) + """, + (pos_opening_shift), + as_dict=1, + ) data = [frappe.get_doc("Sales Invoice", d.name).as_dict() for d in data] @@ -111,41 +134,60 @@ def make_closing_shift_from_opening(opening_shift): taxes = [] payments = [] for detail in opening_shift.get("balance_details"): - payments.append(frappe._dict({ - 'mode_of_payment': detail.get("mode_of_payment"), - 'opening_amount': detail.get("amount") or 0, - 'expected_amount': detail.get("amount") or 0 - })) + payments.append( + frappe._dict( + { + "mode_of_payment": detail.get("mode_of_payment"), + "opening_amount": detail.get("amount") or 0, + "expected_amount": detail.get("amount") or 0, + } + ) + ) for d in invoices: - pos_transactions.append(frappe._dict({ - 'sales_invoice': d.name, - 'posting_date': d.posting_date, - 'grand_total': d.grand_total, - 'customer': d.customer - })) + pos_transactions.append( + frappe._dict( + { + "sales_invoice": d.name, + "posting_date": d.posting_date, + "grand_total": d.grand_total, + "customer": d.customer, + } + ) + ) closing_shift.grand_total += flt(d.grand_total) closing_shift.net_total += flt(d.net_total) closing_shift.total_quantity += flt(d.total_qty) for t in d.taxes: - existing_tax = [tx for tx in taxes if tx.account_head == - t.account_head and tx.rate == t.rate] + existing_tax = [ + tx + for tx in taxes + if tx.account_head == t.account_head and tx.rate == t.rate + ] if existing_tax: existing_tax[0].amount += flt(t.tax_amount) else: - taxes.append(frappe._dict({ - 'account_head': t.account_head, - 'rate': t.rate, - 'amount': t.tax_amount - })) + taxes.append( + frappe._dict( + { + "account_head": t.account_head, + "rate": t.rate, + "amount": t.tax_amount, + } + ) + ) for p in d.payments: existing_pay = [ - pay for pay in payments if pay.mode_of_payment == p.mode_of_payment] + pay for pay in payments if pay.mode_of_payment == p.mode_of_payment + ] if existing_pay: cash_mode_of_payment = frappe.get_value( - "POS Profile", opening_shift.get("pos_profile"), "posa_cash_mode_of_payment") + "POS Profile", + opening_shift.get("pos_profile"), + "posa_cash_mode_of_payment", + ) if not cash_mode_of_payment: cash_mode_of_payment = "Cash" if existing_pay[0].mode_of_payment == cash_mode_of_payment: @@ -154,11 +196,15 @@ def make_closing_shift_from_opening(opening_shift): amount = p.amount existing_pay[0].expected_amount += flt(amount) else: - payments.append(frappe._dict({ - 'mode_of_payment': p.mode_of_payment, - 'opening_amount': 0, - 'expected_amount': p.amount - })) + payments.append( + frappe._dict( + { + "mode_of_payment": p.mode_of_payment, + "opening_amount": 0, + "expected_amount": p.amount, + } + ) + ) closing_shift.set("pos_transactions", pos_transactions) closing_shift.set("payment_reconciliation", payments) @@ -178,11 +224,14 @@ def submit_closing_shift(closing_shift): def submit_printed_invoices(pos_opening_shift): - invoices_list = frappe.get_all("Sales Invoice", filters={ - "posa_pos_opening_shift": pos_opening_shift, - "docstatus": 0, - "posa_is_printed": 1 - }) + invoices_list = frappe.get_all( + "Sales Invoice", + filters={ + "posa_pos_opening_shift": pos_opening_shift, + "docstatus": 0, + "posa_is_printed": 1, + }, + ) for invoice in invoices_list: invoice_doc = frappe.get_doc("Sales Invoice", invoice.name) invoice_doc.submit() diff --git a/posawesome/posawesome/workspace/pos_awesome/pos_awesome.json b/posawesome/posawesome/workspace/pos_awesome/pos_awesome.json index a194ccf1..74cd9ca0 100644 --- a/posawesome/posawesome/workspace/pos_awesome/pos_awesome.json +++ b/posawesome/posawesome/workspace/pos_awesome/pos_awesome.json @@ -1,13 +1,15 @@ { "charts": [], - "content": "[{\"type\":\"header\",\"data\":{\"text\":\"POS Awesome\",\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"POS Awesome App\",\"col\":3}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"POS\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Profile\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Shift\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Delivery Charges\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Offers & Coupons\",\"col\":4}}]", + "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}}]", "creation": "2022-11-29 14:33:45.038200", + "custom_blocks": [], "docstatus": 0, "doctype": "Workspace", "for_user": "", "hide_custom": 0, "icon": "retail", "idx": 0, + "is_hidden": 0, "label": "POS Awesome", "links": [ { @@ -38,34 +40,6 @@ "onboard": 0, "type": "Link" }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Shift", - "link_count": 2, - "onboard": 0, - "type": "Card Break" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Opening Entry", - "link_count": 0, - "link_to": "POS Opening Entry", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Closing Shift", - "link_count": 0, - "link_to": "POS Closing Shift", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, { "hidden": 0, "is_query_report": 0, @@ -139,12 +113,41 @@ "link_type": "Page", "onboard": 0, "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Shift", + "link_count": 2, + "onboard": 0, + "type": "Card Break" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Opening Shift", + "link_count": 0, + "link_to": "POS Opening Shift", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Closing Shift", + "link_count": 0, + "link_to": "POS Closing Shift", + "link_type": "DocType", + "onboard": 0, + "type": "Link" } ], - "modified": "2022-11-29 15:06:41.606620", + "modified": "2023-06-07 17:35:14.887611", "modified_by": "Administrator", "module": "POSAwesome", "name": "POS Awesome", + "number_cards": [], "owner": "Administrator", "parent_page": "", "public": 1, From 247cc570e1c6d2269a2e608a6360025452cf139c Mon Sep 17 00:00:00 2001 From: Yousef Date: Fri, 9 Jun 2023 02:58:04 +0200 Subject: [PATCH 02/12] feat: POS Payments --- posawesome/posawesome/api/m_pesa.py | 12 +- posawesome/posawesome/api/payment_entry.py | 187 ++++- .../mpesa_c2b_register_url.json | 4 +- .../mpesa_payment_register.json | 17 +- .../posawesome/doctype/pos_offer/pos_offer.js | 1 - posawesome/public/js/posapp/Home.vue | 10 +- .../public/js/posapp/components/Navbar.vue | 8 +- .../js/posapp/components/payments/Pay.vue | 759 ++++++++++++++++++ .../js/posapp/components/pos/Customer.vue | 8 + .../public/js/posapp/components/pos/Pos.vue | 6 +- .../posapp/components/pos/UpdateCustomer.vue | 3 +- 11 files changed, 993 insertions(+), 22 deletions(-) create mode 100644 posawesome/public/js/posapp/components/payments/Pay.vue diff --git a/posawesome/posawesome/api/m_pesa.py b/posawesome/posawesome/api/m_pesa.py index 4766839c..4f94bdf3 100644 --- a/posawesome/posawesome/api/m_pesa.py +++ b/posawesome/posawesome/api/m_pesa.py @@ -59,14 +59,18 @@ def get_mpesa_mode_of_payment(company): ) modes_of_payment = [] for mode in modes: - if not mode.mode_of_payment in modes_of_payment: + if mode.mode_of_payment not in modes_of_payment: modes_of_payment.append(mode.mode_of_payment) return modes_of_payment @frappe.whitelist() -def get_mpesa_draft_payments(company, mode_of_payment, mobile_no=None, full_name=None): - filters = {"company": company, "mode_of_payment": mode_of_payment, "docstatus": 0} +def get_mpesa_draft_payments( + company, mode_of_payment=None, mobile_no=None, full_name=None +): + filters = {"company": company, "docstatus": 0} + if mode_of_payment: + filters["mode_of_payment"] = mode_of_payment if mobile_no: filters["msisdn"] = ["like", f"%{mobile_no}%"] if full_name: @@ -77,6 +81,7 @@ def get_mpesa_draft_payments(company, mode_of_payment, mobile_no=None, full_name filters=filters, fields=[ "name", + "transid", "msisdn as mobile_no", "full_name", "posting_date", @@ -85,6 +90,7 @@ def get_mpesa_draft_payments(company, mode_of_payment, mobile_no=None, full_name "mode_of_payment", "company", ], + order_by="posting_date desc", ) return payments diff --git a/posawesome/posawesome/api/payment_entry.py b/posawesome/posawesome/api/payment_entry.py index dfe76ce5..98642a01 100644 --- a/posawesome/posawesome/api/payment_entry.py +++ b/posawesome/posawesome/api/payment_entry.py @@ -1,9 +1,9 @@ # Copyright (c) 2021, Youssef Restom and contributors # For license information, please see license.txt -import frappe, erpnext +import frappe, erpnext, json from frappe import _ -from frappe.utils import nowdate +from frappe.utils import nowdate, getdate from erpnext.accounts.party import get_party_account from erpnext.accounts.utils import get_account_currency from erpnext.accounts.doctype.journal_entry.journal_entry import ( @@ -11,6 +11,7 @@ ) from erpnext.setup.utils import get_exchange_rate from erpnext.accounts.doctype.bank_account.bank_account import get_party_bank_account +from posawesome.posawesome.api.m_pesa import submit_mpesa_payment def create_payment_entry( @@ -122,3 +123,185 @@ def set_paid_amount_and_received_amount( paid_amount = received_amount * conversion_rate return paid_amount, received_amount + + +@frappe.whitelist() +def get_outsanding_invoices(customer, company, currency): + invoices = frappe.get_all( + "Sales Invoice", + filters={ + "customer": customer, + "company": company, + "outstanding_amount": (">", 0), + "docstatus": 1, + "is_return": 0, + "currency": currency, + }, + fields=[ + "name", + "outstanding_amount", + "grand_total", + "due_date", + "posting_date", + "currency", + ], + order_by="due_date asc", + ) + return invoices + + +@frappe.whitelist() +def get_unallocated_payments(customer, company, currency): + unallocated_payment = frappe.get_all( + "Payment Entry", + filters={ + "party": customer, + "company": company, + "docstatus": 1, + "party_type": "Customer", + "payment_type": "Receive", + "unallocated_amount": [">", 0], + "paid_from_account_currency": currency, + }, + fields=[ + "name", + "paid_amount", + "received_amount", + "posting_date", + "unallocated_amount", + "mode_of_payment", + "paid_from_account_currency as currency", + ], + order_by="posting_date asc", + ) + return unallocated_payment + + +@frappe.whitelist() +def process_pos_payment(payload): + data = json.loads(payload) + data = frappe._dict(data) + + # validate data + if not data.customer: + frappe.throw(_("Customer is required")) + if not data.company: + frappe.throw(_("Company is required")) + if not data.currency: + frappe.throw(_("Currency is required")) + if not data.pos_profile_name: + frappe.throw(_("POS Profile is required")) + if not data.pos_opening_shift_name: + frappe.throw(_("POS Opening Shift is required")) + + company = data.company + currency = data.currency + customer = data.customer + pos_profile_name = data.pos_profile_name + pos_opening_shift_name = data.pos_opening_shift_name + today = nowdate() + + new_payments_entry = [] + all_payments_entry = [] + errors = [] + reconcile_doc = None + + # first process mpesa payments + if len(data.selected_mpesa_payments) > 0 and data.total_selected_mpesa_payments > 0: + for mpesa_payment in data.selected_mpesa_payments: + try: + new_mpesa_payment = submit_mpesa_payment( + mpesa_payment.get("name"), customer + ) + new_payments_entry.append(new_mpesa_payment) + all_payments_entry.append(new_mpesa_payment) + except Exception as e: + errors.append(e) + + # then process the new payments + if len(data.payment_methods) > 0 and data.total_payment_methods > 0: + for payment_method in data.payment_methods: + try: + if not payment_method.get("amount"): + continue + new_payment_entry = create_payment_entry( + company=company, + customer=customer, + currency=currency, + amount=payment_method.get("amount"), + mode_of_payment=payment_method.get("mode_of_payment"), + posting_date=today, + reference_no=pos_opening_shift_name, + reference_date=today, + submit=1, + ) + new_payments_entry.append(new_payment_entry) + all_payments_entry.append(new_payment_entry) + except Exception as e: + errors.append(e) + + # then then reconcile the new payments and the unallocated payments with the outstanding invoices + if len(data.selected_invoices) > 0 and data.total_selected_invoices > 0: + if len(data.selected_payments) > 0 and data.total_selected_payments > 0: + # add the unallocated payments to the all payments entry + for selected_payment in data.selected_payments: + all_payments_entry.append(selected_payment) + + if len(all_payments_entry) > 0: + # sort the all payments entry by posting date + all_payments_entry = sorted( + all_payments_entry, + key=lambda k: getdate(str(k.get("posting_date"))), + reverse=True, + ) + all_invoices_list = sorted( + data.selected_invoices, + key=lambda k: getdate(k.get("posting_date")), + reverse=True, + ) + reconcile_doc = frappe.new_doc("Payment Reconciliation") + reconcile_doc.party_type = "Customer" + reconcile_doc.party = customer + reconcile_doc.company = company + reconcile_doc.receivable_payable_account = get_party_account( + "Customer", customer, company + ) + reconcile_doc.get_unreconciled_entries() + args = { + "invoices": [], + "payments": [], + } + for invoice in all_invoices_list: + args["invoices"].append( + { + "invoice_type": "Sales Invoice", + "invoice_number": invoice.get("name"), + "invoice_date": invoice.get("posting_date"), + "amount": invoice.get("grand_total"), + "outstanding_amount": invoice.get("outstanding_amount"), + "currency": invoice.get("currency"), + "exchange_rate": 0, + } + ) + for payment in all_payments_entry: + args["payments"].append( + { + "reference_type": "Payment Entry", + "reference_name": payment.get("name"), + "posting_date": payment.get("posting_date"), + "amount": payment.get("unallocated_amount"), + "unallocated_amount": payment.get("unallocated_amount"), + "difference_amount": 0, + "currency": payment.get("currency"), + "exchange_rate": 0, + } + ) + reconcile_doc.allocate_entries(args) + reconcile_doc.reconcile() + + return { + "new_payments_entry": new_payments_entry, + "all_payments_entry": all_payments_entry, + "errors": errors, + "reconcile_doc": reconcile_doc, + } diff --git a/posawesome/posawesome/doctype/mpesa_c2b_register_url/mpesa_c2b_register_url.json b/posawesome/posawesome/doctype/mpesa_c2b_register_url/mpesa_c2b_register_url.json index 4a815dd6..e801df0f 100644 --- a/posawesome/posawesome/doctype/mpesa_c2b_register_url/mpesa_c2b_register_url.json +++ b/posawesome/posawesome/doctype/mpesa_c2b_register_url/mpesa_c2b_register_url.json @@ -73,10 +73,11 @@ ], "index_web_pages_for_search": 1, "links": [], - "modified": "2021-11-18 05:08:03.509002", + "modified": "2023-06-07 17:56:04.569137", "modified_by": "Administrator", "module": "POSAwesome", "name": "Mpesa C2B Register URL", + "naming_rule": "By fieldname", "owner": "Administrator", "permissions": [ { @@ -124,5 +125,6 @@ ], "sort_field": "modified", "sort_order": "DESC", + "states": [], "track_changes": 1 } \ No newline at end of file diff --git a/posawesome/posawesome/doctype/mpesa_payment_register/mpesa_payment_register.json b/posawesome/posawesome/doctype/mpesa_payment_register/mpesa_payment_register.json index 7eda9796..35f5bf2f 100644 --- a/posawesome/posawesome/doctype/mpesa_payment_register/mpesa_payment_register.json +++ b/posawesome/posawesome/doctype/mpesa_payment_register/mpesa_payment_register.json @@ -23,6 +23,7 @@ "lastname", "column_break_14", "posting_date", + "posting_time", "company", "default_currency", "customer", @@ -157,9 +158,9 @@ "options": "Customer" }, { - "default": "Now", + "default": "Today", "fieldname": "posting_date", - "fieldtype": "Datetime", + "fieldtype": "Date", "in_list_view": 1, "in_preview": 1, "in_standard_filter": 1, @@ -218,16 +219,25 @@ "fieldname": "submit_payment", "fieldtype": "Check", "label": "Submit Payment " + }, + { + "default": "Now", + "fieldname": "posting_time", + "fieldtype": "Time", + "label": "Posting Time", + "no_copy": 1, + "read_only": 1 } ], "in_create": 1, "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2021-11-19 23:05:24.242365", + "modified": "2023-06-07 22:24:09.518620", "modified_by": "Administrator", "module": "POSAwesome", "name": "Mpesa Payment Register", + "naming_rule": "Expression (old style)", "owner": "Administrator", "permissions": [ { @@ -280,6 +290,7 @@ "show_preview_popup": 1, "sort_field": "modified", "sort_order": "DESC", + "states": [], "title_field": "customer", "track_changes": 1 } \ No newline at end of file diff --git a/posawesome/posawesome/doctype/pos_offer/pos_offer.js b/posawesome/posawesome/doctype/pos_offer/pos_offer.js index 2f2709e4..11defabf 100644 --- a/posawesome/posawesome/doctype/pos_offer/pos_offer.js +++ b/posawesome/posawesome/doctype/pos_offer/pos_offer.js @@ -55,7 +55,6 @@ frappe.ui.form.on('POS Offer', { const controllers = (frm) => { - console.info("controllers"); frm.toggle_display('item', frm.doc.apply_on === 'Item Code'); frm.toggle_reqd('item', frm.doc.apply_on === 'Item Code'); diff --git a/posawesome/public/js/posapp/Home.vue b/posawesome/public/js/posapp/Home.vue index c6cd2d60..a89834f2 100644 --- a/posawesome/public/js/posapp/Home.vue +++ b/posawesome/public/js/posapp/Home.vue @@ -2,9 +2,7 @@ - - - + @@ -12,16 +10,18 @@ + + diff --git a/posawesome/public/js/posapp/components/pos/Customer.vue b/posawesome/public/js/posapp/components/pos/Customer.vue index b8fcc767..bff2b7e4 100644 --- a/posawesome/public/js/posapp/components/pos/Customer.vue +++ b/posawesome/public/js/posapp/components/pos/Customer.vue @@ -52,11 +52,15 @@ +
+ +
\ No newline at end of file + diff --git a/posawesome/public/js/posapp/format.js b/posawesome/public/js/posapp/format.js new file mode 100644 index 00000000..4625fc6b --- /dev/null +++ b/posawesome/public/js/posapp/format.js @@ -0,0 +1,86 @@ +export default { + methods: { + flt (value, precision, number_format, rounding_method) { + if (!precision && precision != 0) { + precision = this.currency_precision || 2; + } + if (!rounding_method) { + rounding_method = "Banker's Rounding (legacy)"; + } + return flt(value, precision, number_format, rounding_method); + }, + formtCurrency (value, precision) { + const fomrat = get_number_format(this.pos_profile?.currency); + value = format_number( + value, + fomrat, + precision || this.currency_precision || 2 + ); + return value; + }, + formtFloat (value, precision) { + const fomrat = get_number_format(this.pos_profile.currency); + value = format_number(value, fomrat, precision || this.float_precision || 2); + return value; + }, + setFormatedCurrency (el, field_name, precision, no_negative = false, $event) { + let value = 0; + try { + // make sure it is a number and positive + let _value = parseFloat($event); + if (!isNaN(_value)) { + value = _value; + } + if (no_negative && value < 0) { + value = value * -1; + } + value = this.formtCurrency($event, precision); + } catch (e) { + console.error(e); + value = 0; + } + // check if el is an object + if (typeof el === "object") { + el[field_name] = value; + } + else { + this[field_name] = value; + } + + + return value; + }, + setFormatedFloat (el, field_name, precision, no_negative = false, $event) { + let value = 0; + try { + // make sure it is a number and positive + // value = parseFloat($event); + if (isNaN(value)) { + value = 0; + } else if (no_negative && value < 0) { + value = value * -1; + } + value = this.formtCurrency($event, precision); + } catch (e) { + console.error(e); + value = 0; + } + // check if el is an object + if (typeof el === "object") { + el[field_name] = value; + } + else { + this[field_name] = value; + } + return value; + }, + currencySymbol (currency) { + return get_currency_symbol(currency); + }, + isNumber (value) { + const pattern = /^-?(\d+|\d{1,3}(\.\d{3})*)(,\d+)?$/; + return pattern.test(value) || "invalid number"; + + } + }, +}; \ No newline at end of file From ed02da83b9be726c6043178fa2eb983046ed783d Mon Sep 17 00:00:00 2001 From: Yousef Date: Sat, 10 Jun 2023 23:16:39 +0200 Subject: [PATCH 04/12] fix: invoice amount & items amount --- .../public/js/posapp/components/pos/Invoice.vue | 12 ++++++------ posawesome/public/js/posapp/format.js | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/posawesome/public/js/posapp/components/pos/Invoice.vue b/posawesome/public/js/posapp/components/pos/Invoice.vue index 86577ccc..c760c2e0 100644 --- a/posawesome/public/js/posapp/components/pos/Invoice.vue +++ b/posawesome/public/js/posapp/components/pos/Invoice.vue @@ -175,7 +175,7 @@ >