diff --git a/SO_to_Inv/readSO.py b/SO_to_Inv/readSO.py index 555cdda..49ef292 100644 --- a/SO_to_Inv/readSO.py +++ b/SO_to_Inv/readSO.py @@ -9,7 +9,7 @@ import timeit import os import pythoncom # from icecream import ic - +from decimal import Decimal # ic.configureOutput(includeContext=True, ) class SalesOrderQuery: @@ -204,6 +204,7 @@ class SalesOrderQuery: # Memo = self.create_sub_element(ET, InvoiceAdd, "Memo", self.DN['Memo'], 10 ) disc_amount = 0 for soidx, salesorder in enumerate(self.SalesOrderList): + disc_amount = 0 if 'TxnID' in salesorder: SOTxnId = salesorder['TxnID'] # disc_amount+=int(salesorder['Disc_Amount']) @@ -254,8 +255,8 @@ class SalesOrderQuery: # print(f"replyfrom qbxml:{self.connect_to_quickbooks(qbxml_query)}") # print([s for s in qbxml_query.split('\n') if s.strip(' ') != '']) - print(self.pprintXml(qbxml_query)) - return qbxml_query + # print(self.pprintXml(qbxml_query)) + return self.pprintXml(qbxml_query) def connect_to_quickbooks(self, qbxml_query): @@ -306,7 +307,7 @@ class SalesOrderQuery: else: return False, status_code - def get_discperpcs(self, ItemFullName, Rate:float): + def get_discperpcs(self, ItemFullName, Rate): discPerPcs = 0 if self.Customer: if self.Customer[2]: @@ -321,7 +322,7 @@ class SalesOrderQuery: def _get_sales_order_header(self, response_string, includefullInvoiced=False): print('_get_sales_order_header') - # print(f'responsestring:{self.pprintXml(response_string)}') + print(f'responsestring sales order header:{self.pprintXml(response_string)}') QBXML = ET.fromstring(response_string) datadict = {} SalesOrderdict = {} @@ -360,27 +361,36 @@ class SalesOrderQuery: for SalesOrderLineRet in SalesOrderLineRet: discPerItem = 0 discPerPcs = 0 + convertQTY = 1 TxnLineID = SalesOrderLineRet.find('TxnLineID').text ItemFullName = SalesOrderLineRet.find('ItemRef/FullName') if ItemFullName is None: print("no itemfullname") - break + continue else: ItemFullName=ItemFullName.text # print(ItemFullName) Quantity = SalesOrderLineRet.find('Quantity').text UnitOfMeasure = SalesOrderLineRet.find('UnitOfMeasure').text + + ### modified if UOM has ConvertQTY: '_' or ' of '-> in OverrideUOMSetRef + if '_' in UnitOfMeasure: + convertQTY = int(UnitOfMeasure.split('_')[1]) OverrideUOMSetRef = SalesOrderLineRet.find('OverrideUOMSetRef/FullName') if OverrideUOMSetRef != None: OverrideUOMSetRef = OverrideUOMSetRef.text - Rate = float(SalesOrderLineRet.find('Rate').text) + if 'of' in OverrideUOMSetRef and UnitOfMeasure.upper() == 'BOX': + convertQTY = int(OverrideUOMSetRef.split('of')[1]) + print(f'OverrideUOMSetRef:{OverrideUOMSetRef}') + ### - Amount = float(SalesOrderLineRet.find('Amount').text) + Rate = Decimal(SalesOrderLineRet.find('Rate').text) + Amount = Decimal(SalesOrderLineRet.find('Amount').text) # if self.SPPriceLevelName: Invoiced = SalesOrderLineRet.find('Invoiced').text LineIsManuallyClosed = SalesOrderLineRet.find('IsManuallyClosed').text # print(TxnLineID, ItemFullName) - BackOrdered = float(Quantity) - float(Invoiced) + BackOrdered = Decimal(Quantity) - Decimal(Invoiced) if BackOrdered > 0 and LineIsManuallyClosed.lower() == 'false' : # ic(self.Customer) discPerPcs = self.get_discperpcs(ItemFullName, Rate) @@ -408,6 +418,7 @@ class SalesOrderQuery: 'LineIsManuallyClosed':LineIsManuallyClosed, 'discPerItem':discPerItem, # backorder qty * disc per pcs 'discPerPcs':discPerPcs, + 'convertQTY':convertQTY, } SalesOrderdict['SalesOrderLineRet'].append(SalesOrderLinedict) SalesOrderdict['Disc_Amount']=disc_amount diff --git a/django/Invoice/templates/Invoice/so_details_form.html b/django/Invoice/templates/Invoice/so_details_form.html index 0a276fc..e06d20b 100644 --- a/django/Invoice/templates/Invoice/so_details_form.html +++ b/django/Invoice/templates/Invoice/so_details_form.html @@ -26,12 +26,8 @@ {% for so_dict in objects %} - {{so_dict}} - - {{so_dict.RefNumber}} + {% for so_line in so_dict.SalesOrderLineRet %} - {{so_dict.RefNumber}} - {{so_line.ItemFullName}} @@ -43,18 +39,18 @@ {% endfor %}
- +
{{ so_dict.TxnDate }} {{ so_dict.RefNumber }} - {{ so_line.Quantity }} - {{ so_line.Invoiced }} - + {% widthratio so_line.Quantity so_line.convertQTY 1 %} + {% widthratio so_line.Invoiced so_line.convertQTY 1 %} + {{ so_line.UOM }} - + {% endfor %} {% endfor %} diff --git a/django/Invoice/views.py b/django/Invoice/views.py index f494b01..8540818 100644 --- a/django/Invoice/views.py +++ b/django/Invoice/views.py @@ -15,6 +15,7 @@ import os import pandas as pd from django.conf import settings from icecream import ic +from decimal import Decimal ic.configureOutput(includeContext= True) @@ -197,21 +198,40 @@ def save_inv(request): del data['other_rate'] print(f'others:{others}') - # print(f"datadict:{data}") + print(f"datadict:{data}") + required_data = ['RefNumber', 'CustomerFullName', 'TxnID', 'TxnDate', 'TotalAmount', 'TxnLineID', 'ItemFullName', + 'Quantity', 'UOM', 'Rate', 'Amount', 'Invoiced', 'LineIsManuallyClosed', 'backordered', 'rate', 'convertQTY'] + if 'so_field' not in data: + return HttpResponse("no Selected Items. Please select at least 1 item to be invoiced.") + for _ in required_data: + if _ not in data: + return HttpResponse(f"Required data not returned from the form: {_}") + + ### retrieve only the selected so_field ### + so_field = data['so_field'] + del data['so_field'] + selectedItems = [] + for _ in so_field: + if _ not in data['TxnLineID']: + return HttpResponse(f"One of the TxnLineID is not valid: {_}") + data_idx = data['TxnLineID'].index(_) try: df = pd.DataFrame(data) print(df) + df = df[df['TxnLineID'].isin(so_field)].reset_index() + print(df) except: print(Exception) return HttpResponse("DataFrame Error") # print(f'json:{df.to_json(orient="records")}') web_dict = df.to_dict("records") # print(f'web_dict:{web_dict}' ) - web_dict = sorted(web_dict, key=lambda x: x['TxnLineID']) + web_dict = sorted(web_dict, key=lambda x: x['TxnID']) # print(f'Sorted web_dict:{web_dict}' ) if ('so_field' in request.POST) and ('customer_fullname' in request.POST): print(request.POST.getlist('so_field')) - open_sales_orders_TxnID = unique(request.POST.getlist('so_field')) + # open_sales_orders_TxnID = unique(request.POST.getlist('so_field')) + open_sales_orders_TxnID = unique(df['TxnID'].to_list()) customer_fullname = request.POST.get('customer_fullname') print(f'Customer_fullname:{customer_fullname} -> request values:{open_sales_orders_TxnID}') ### get the SO detail @@ -246,28 +266,34 @@ def save_inv(request): for tu_line_ret in tu_['SalesOrderLineRet']: # print(tu_line_ret) if web['TxnLineID']==tu_line_ret['TxnLineID'] and web['ItemFullName']==tu_line_ret['ItemFullName']: - if 0 < float(web['backordered']) <= float(tu_line_ret['BackOrdered']): + ### modified back the rate and backordered using convertQTY ### + convertQTY = int(tu_line_ret['convertQTY']) + webbackordered = Decimal(web['backordered']) * convertQTY + webrate = Decimal(web['rate']) / convertQTY + ### + if 0 < webbackordered <= Decimal(tu_line_ret['BackOrdered']): # print('put in list') discPerPcs=0 discPerItem=0 - if float(web['rate']) == float(tu_line_ret['Rate']): - discPerPcs = ini.get_discperpcs(web['ItemFullName'], float(web['rate'])) - elif float(web['rate']) < float(tu_line_ret['Rate']): - discPerPcs = float(tu_line_ret['Rate']) - float(web['rate']) - discPerItem = float(web['backordered']) * discPerPcs + if webrate == Decimal(tu_line_ret['Rate']): + discPerPcs = ini.get_discperpcs(web['ItemFullName'], webrate) + elif webrate < Decimal(tu_line_ret['Rate']): + discPerPcs = Decimal(tu_line_ret['Rate']) - webrate + discPerItem = webbackordered * discPerPcs disc_amount += discPerItem SalesOrderLinedict = {'TxnLineID':web['TxnLineID'], - 'ItemFullName':web['ItemFullName'], + 'ItemFullName':tu_line_ret['ItemFullName'], 'Quantity':tu_line_ret['Quantity'], 'UOM':tu_line_ret['UOM'], - 'Rate':float(web['rate']), - 'Amount':float(tu_line_ret['Amount']), - 'BackOrdered':float(web['backordered']), + 'Rate':webrate, + 'Amount':Decimal(tu_line_ret['Amount']), + 'BackOrdered':webbackordered, 'Invoiced':tu_line_ret['Invoiced'], 'LineIsManuallyClosed':tu_line_ret['LineIsManuallyClosed'], 'discPerItem':discPerItem, # backorder qty * disc per pcs 'discPerPcs':discPerPcs, + 'convertQTY':tu_line_ret['convertQTY'] } # print(f'salesorderlineddict:{SalesOrderLinedict}') _salesorderlineret = dict_['SalesOrderLineRet'] @@ -277,7 +303,11 @@ def save_inv(request): break break print(f'last:{dict_}') - if dict_ != data_to_save[-1]: #append the last dict_ + print(f'datatosaveonly:{data_to_save}') + if not data_to_save: + dict_['Disc_Amount']=disc_amount + data_to_save.append(dict_) + elif dict_ != data_to_save[-1]: #append the last dict_ dict_['Disc_Amount']=disc_amount data_to_save.append(dict_) print('save the last dict') @@ -296,9 +326,14 @@ def save_inv(request): print(invoiceaddQBXML) result=None - result = ini.connect_to_quickbooks(ini.create_invoiceadd_QBXML()) + # result = ini.connect_to_quickbooks(ini.create_invoiceadd_QBXML()) print("RESULT:") print(result) + if result and ini.status_ok(result): + pass + + messages.success(request, 'Invoice Has Been SAVED') + return redirect('Invoice:show_customer') return render(request, "Invoice/so_details_form.html", context) else: return HttpResponse(f"You cannot Save, because There Is No Open Sales Order for Customer: {customer_fullname}") diff --git a/django/templates/base.html b/django/templates/base.html index dc46c24..4b510de 100644 --- a/django/templates/base.html +++ b/django/templates/base.html @@ -6,8 +6,8 @@ - {% comment %} - {% endcomment %} + + @@ -83,6 +83,17 @@ + {% if messages %} + {% for message in messages %} + + {% endfor %} + {% endif %} {% block body %}{% endblock body %}