def AutoTransferReceiptItems(self, ReceiptID): ''' Go through the receipt items and check to see if the item is an automatic transfer item, that is, the item is marked as a non- dispensable item (ie. it cannot be dispensed) so we need to transfer it automatically. Registration and bed assignment are examples of such items. NOTE: dispensing for automatic items should only happen AFTER payment. If the item is not paid for then make sure it is not marked dispensed ''' log.debug('AutoTransferReceiptItems'); receipt = model.InvReceipt.get(ReceiptID) for item in receipt.CatalogItems: if item.IsPaid() and (not item.CatalogItem.IsDispensable): #find all transfers (normally just one) and mark them complete for stocklocation in item.StockItems: for transfer in stocklocation.TransfersToHere: if not transfer.IsComplete: transfer.IsComplete = True transfer.DateTransferred = model.cur_date_time() transfer.FromStockLocation.Quantity -= transfer.Qty transfer.ToStockLocation.Quantity += transfer.Qty log.debug('....Auto dispensing item %d' % item.id) elif (not item.IsPaid()) and (not item.CatalogItem.IsDispensable): #find all transfers (normally just one) and mark them not complete for stocklocation in item.StockItems: for transfer in stocklocation.TransfersToHere: if transfer.IsComplete: transfer.FromStockLocation.Quantity += transfer.Qty transfer.ToStockLocation.Quantity -= transfer.Qty transfer.IsComplete = False log.debug('....Marking not dispensed item %d' % item.id)
def BillingRefund(self, ReceiptID, CashAmt, **kw): ''' Refund some cash to a customer Only allow refunds if the customer has credit, and only up to the credit amount If a refund cannot be fulfilled as requested, then don't do any refund at all, even if the customer has some credit ''' # Load the customer Customer = model.InvReceipt.get(ReceiptID).Customer if (Customer.CalcCashBalance() >= 0): ErrorMsg = 'Refund rejected, Customer has no credit' NextLink = 'index?receipt_id=%d' % ReceiptID raise cherrypy.HTTPRedirect('DataEntryError?error=%s&next_link=%s' % (ErrorMsg, NextLink)) elif (CashAmt <= 0): ErrorMsg = 'Refund ignored, cannot refund a 0 or negative amount' NextLink = 'index?receipt_id=%d' % ReceiptID raise cherrypy.HTTPRedirect('DataEntryError?error=%s&next_link=%s' % (ErrorMsg, NextLink)) elif (Customer.CalcBalance() + CashAmt > 0): ErrorMsg = 'Refund rejected, Customer has insufficient credit' NextLink = 'index?receipt_id=%d' % ReceiptID raise cherrypy.HTTPRedirect('DataEntryError?error=%s&next_link=%s' % (ErrorMsg, NextLink)) else: payment = model.InvCustomerPayment(CustomerID=Customer.id, DatePaid=model.cur_date_time(),\ Amount=-CashAmt,Notes='Cash refund from user id: %s' % (model.cur_user_id())) raise cherrypy.HTTPRedirect('index?receipt_id=%d' % ReceiptID)
def CustomerPayment(self, id='',Id='', Op='', CustomerID='', **kw): if Id != '': id = Id if id != '': try: int_id = int(id) record = model.InvCustomerPayment.get(int_id) except (ValueError, SQLObjectNotFound): int_id = -1 else: int_id = -1 #Find initial values for our data record #Vendor -> Customer #Amount NEW #ValidOn -> DatePaid if int_id > 0: Id_data = record.id Name_data = record.Name() Notes_data = record.Notes DatePaid_data = record.DatePaid Amount_data = record.Amount #ForeignKeys try: Customer_data = record.CustomerID Customer_display = record.Customer.Name + ' ('+str(record.CustomerID)+')' except AttributeError: Customer_data = '' Customer_display = 'None' #MultiJoin and RelatedJoin else: Id_data = '' Name_data = 'New entry' Notes_data = '' DatePaid_data = model.cur_date_time() Amount_data = '0.0' #ForeignKeys if CustomerID != '': Customer_data = CustomerID Customer_display = model.InvCustomer.get(int(CustomerID)).Name else: Customer_data = '' Customer_display = 'None' #MultiJoin and RelatedJoin #Special manipulations for new records if Op == 'CopyIntoNew': Id_data = '' id = '' #Construct our display fields Id = dict(id="cp_Id", name="Id", label="Id", type="Hidden",attr={}, data=Id_data) Name = dict(id="cp_Name", name="Name", label="Name", type="StringRO",attr=dict(length=50), data=Name_data) DatePaid = dict(id="cp_DatePaid", name="DatePaid", label="Date paid", type="DateTime",attr=dict(), data=DatePaid_data) Amount = dict(id="cp_Amount", name="Amount", label="Amount", type="Currency",attr=dict(), data=Amount_data) Notes = dict(id="cp_Notes", name="Notes", label="Notes", type="String",attr=dict(length=50), data=Notes_data) #ForeignKeys SrchCustomerName = dict(id="cp_SrchCustomerName", name="Name", label="Name", type="String",attr=dict(length=25), data='') Customer = dict(id="cp_Customer", name="Customer", label="Customer", type="ForeignKey",attr=dict(srchUrl="CustomerSearch",lookupUrl="CustomerGet", edit_url='Customer', srchFields=[SrchCustomerName]), data=Customer_data, init_display=Customer_display) #MultiJoin #Fields fields = [Id, Name, Customer, Amount, DatePaid, Notes] #Configure any of the links that might need configuring if id == '': CustomerPaymentMenu = 'CustomerPaymentMenu' else: CustomerPaymentMenu = 'CustomerPaymentMenu?id=' + id #RETURN VALUES HERE return dict(id=id, Name='CustomerPayment', Label='Customer payment entry', Fields=fields, FieldsSrch=[Name], Read='CustomerPayment', Add='CustomerPaymentSave', Del='CustomerPaymentDel', UnDel='CustomerPaymentUnDel', Edit='CustomerPayment', Save='CustomerPaymentSave', SrchUrl='CustomerPaymentSearch', MenuBar=CustomerPaymentMenu)
def MakeReceiptPayment(self, ReceiptID, TotalCashAmt=0, CashAmt=0, CashNotes='', InsrAmt=0, InsrNotes='', **kw): ''' Go through all the receipt items in the receipt and mark the items as paid for. Create a new payment record (marking the date and amount when money was exchanged). Double check the items on the receipt and make sure they are marked as paid if no payments are outstanding. ''' log.debug('MakeReceiptPayment') try: record = model.InvReceipt.get(ReceiptID) except (ValueError, SQLObjectNotFound): #happens when the conversion fails or the record is not found return dict(flash='No record to make payment for') # Make our payment record if TotalCashAmt !=0: payment = model.InvCustomerPayment(CustomerID=record.CustomerID, DatePaid=model.cur_date_time(),\ Amount=TotalCashAmt,Notes=CashNotes) # Figure out how much money the customer has for spending - without including the current receipt amount CurrCredit = -record.Customer.CalcBalance(DoNotIncludReceiptID=ReceiptID) log.debug('....Current credit: %d' % CurrCredit) # Make sure no one is trying to cheat the program by forcing an Insurance payment if self.IsSelfPay(ReceiptID) and InsrAmt > 0: CashAmt += InsrAmt InsrAmt = 0 # Go through and confirm the unit cost again (and verify that all receipt items have been assigned to stock) for item in record.CatalogItems: # Check to make sure all the items are assigned to a particular stock item if len(item.StockItems) == 0: # Hmmm... somehow the item wasn't assigned to a stock location # At this point, we'll just assign the next available stock location to the item # We'll force a re-adjustment if the quantities cannot be fulfilled (no option at this point?) StockItemID = item.CatalogItem.NextStockItemID(item.Quantity) if StockItemID == None: # Insufficient stock to fulfill request, try to partially fill it StockItemID = item.CatalogItem.NextStockItemID() if StockItemID == None: # No stock at all, set the receipt item to zero!!!!! item.Quantity = 0 item.UnitCost = 0 if StockItemID != None: # Complete the assignment StockItem = model.InvStockItem.get(StockItemID) if item.Quantity > StockItem.QtyAvailable(): item.Quantity = StockItem.QtyAvailable() StockLocationIDs = StockItem.FindStockLocationIDs(item.Quantity) if record.Customer.InventoryLocationID == None: LocationID = self.GetDefaultCustomerLocationID() else: LocationID = record.Customer.InventoryLocationID new_stocklocation = model.InvStockLocation(StockItemID=StockItemID, \ LocationID=LocationID, ReceiptID=item.id, Quantity=0.0, IsConsumed=True, IsSold=True) #Create the stock transfer log.debug('......creating %d new stock transfer(s)' % len(StockLocationIDs)) CurrQuantity = item.Quantity # Keep track of the current quantity transferred for stocklocationid in StockLocationIDs: StockLocation = model.InvStockLocation.get(stocklocationid) if CurrQuantity <= StockLocation.QtyAvailable(): TransferQty = CurrQuantity CurrQuantity = 0 else: TransferQty = StockLocation.QtyAvailable() CurrQuantity = CurrQuantity - TransferQty new_stck_transfer = model.InvStockTransfer(FromStockLocationID=stocklocationid, \ ToStockLocation=new_stocklocation.id, Qty=TransferQty) if CurrQuantity <= 0: break #Update the unit price item.UnitCost = item.StockItems[0].StockItem.SalePrice else: item.UnitCost = item.StockItems[0].StockItem.SalePrice # Apply the payment to our Receipt and linked items. Note: record = current receipt record.TotalPayment = record.TotalPaymentCalc() NewAmt = CurrCredit + InsrAmt # This is what we have to spend record.TotalPaid += NewAmt # Cap the total paid to the payment required if record.TotalPaid > record.TotalPayment: record.TotalPaid = record.TotalPayment # For cash amounts in excess of the required payment, limit the amount applied if CashAmt > record.TotalPayment: CashAmt = record.TotalPayment # Limit insurance amount payments if InsrAmt > record.TotalPayment: InsrAmt = record.TotalPayment # For combo payments, Insurance is reduced and cash is used as the greater part when needed. if (CashAmt + InsrAmt) > record.TotalPayment: InsrAmt = record.TotalPayment - CashAmt log.debug('....Money to spend: %d' % record.TotalPaid) # The TotalAmt is what we have for making payments on our stock location items TotalAmt = record.TotalPaid record.TotalSelfPay = CashAmt # Shows how much of the bill is Cash amount record.SelfPayNotes = CashNotes record.TotalInsurance = InsrAmt # How much of this bill is paid by insurance record.InsuranceNotes = InsrNotes # Update payments on the stock items for accounting and dispensing for item in record.CatalogItems: if (not item.IsPaid()) and (not item.IsDispensed()):#Don't change items which are paid for or dispensed log.debug('....Updating payments on stock location') PartPay = round(item.Quantity * item.UnitCost) - item.TotalPaid() if PartPay > 0: #We need to apply new payments to our stock (as much as we have money for) if PartPay > TotalAmt: PartPay = TotalAmt TotalAmt = 0 log.debug('....Too little money') else: TotalAmt -= PartPay for stocklocation in item.StockItems: stockpaid = round(stocklocation.QtyAfterTransfers() * stocklocation.StockItem.SalePrice) - stocklocation.TotalPaid log.debug('....StockLocation %d with Rs. %d' % (stocklocation.id,stockpaid)) if stockpaid > 0: # We still have more to pay if stockpaid > PartPay: stockpaid = PartPay PartPay = 0 log.debug('....Too little rupees') else: PartPay -= stockpaid stocklocation.TotalPaid += round(stockpaid) elif stockpaid < 0: # we have reduced stock from this transfer PartPay -= stockpaid stocklocation.TotalPaid = round(stocklocation.QtyAfterTransfers() * stocklocation.StockItem.SalePrice) else: #We've reduced amounts and are actually refunding money at this point. Fix our payment records TotalAmt -= PartPay # Go through all the stock items and adjust the TotalPaid. Don't worry about keeping track # since we've reduced cost for stocklocation in item.StockItems: stocklocation.TotalPaid = round(stocklocation.QtyAfterTransfers() * stocklocation.StockItem.SalePrice) else: TotalAmt -= item.TotalPaid() # For auto-transfer items, transfer them after payment self.AutoTransferReceiptItems(ReceiptID) return self.LoadPatientData(ReceiptID=ReceiptID)
def StockTransferRequest(self, id='',Id='', Op='', **kw): if Id != '': id = Id if id != '': try: int_id = int(id) record = model.InvStockTransferRequest.get(int_id) except (ValueError, SQLObjectNotFound): int_id = -1 else: int_id = -1 #Find initial values for our data record if int_id > 0: Id_data = record.id Name_data = record.Name() Notes_data = record.Notes RequestedBy_data = record.RequestedBy RequestedOn_data = record.RequestedOn RequiredBy_data = record.RequiredBy #ForeignKeys try: ForLocation_data = record.ForLocation.id ForLocation_display = record.ForLocation.Name + ' ('+str(record.ForLocation.id)+')' except AttributeError: ForLocation_data = '' ForLocation_display = 'None' #MultiJoin and RelatedJoin Items_data = 'There are ' + str(len(record.Items)) + ' records' if record.Status == 'deleted': DisplayMessage_data = "NOTE: This record is marked deleted!" else: DisplayMessage_data = "" else: Id_data = '' Name_data = '' Notes_data = '' RequestedBy_data = model.cur_user_id() RequestedOn_data = model.cur_date_time().strftime('%Y-%m-%d') RequiredBy_data = model.cur_date_time().strftime('%Y-%m-%d') #ForeignKeys ForLocation_data = '' ForLocation_display = 'None' #MultiJoin and RelatedJoin Items_data = 'There are no records' #Special manipulations for new records if Op == 'CopyIntoNew': #ForeignKeys Name_data = '' RequestedBy_data = model.cur_user_id() RequestedOn_data = model.cur_date_time().strftime('%Y-%m-%d') RequiredBy_data = model.cur_date_time().strftime('%Y-%m-%d') #MultiJoin and RelatedJoin Items_data = 'There are no records' Id_data = '' id = '' #Construct our display fields Id = dict(id="str_Id", name="Id", label="Id", type="Hidden",attr={}, data=Id_data) Name = dict(id="str_Name", name="Name", label="Name", type="StringRO",attr=dict(length=50), data=Name_data) RequestedBy = dict(id="str_RequestedBy", name="RequestedBy", label="Requested by", type="StringRO",attr=dict(length=50), data=RequestedBy_data) RequestedOn = dict(id="str_RequestedOn", name="RequestedOn", label="Requested on", type="DateTime",attr=dict(), data=RequestedOn_data) RequiredBy = dict(id="str_RequiredBy", name="RequiredBy", label="Required by", type="DateTime",attr=dict(), data=RequiredBy_data) Notes = dict(id="str_Notes", name="Notes", label="Notes", type="String",attr=dict(length=50), data=Notes_data) #ForeignKeys SrchLocationName = dict(id="str_SrchLocationName", name="Name", label="Name", type="String",attr=dict(length=25), data='') ForLocation = dict(id="str_ForLocation", name="ForLocation", label="ForLocation", type="ForeignKey",attr=dict(srchUrl="LocationSearch",lookupUrl="LocationGet", edit_url='Location', srchFields=[SrchLocationName]), data=ForLocation_data, init_display=ForLocation_display) #MultiJoin Items = dict(id="str_Items", name="Items", label="Items", type="MultiJoin",attr=dict(displayUrl="StockTransferRequestMultiJoinList",listUrl="StockTransferRequestMultiJoinList", linkUrl="StockTransferRequestItem"), data=Items_data) #Fields fields = [Id, Name, RequestedBy, RequestedOn, RequiredBy, ForLocation, Items, Notes] #Configure any of the links that might need configuring if id == '': StockTransferRequestMenu = 'StockTransferRequestMenu' else: StockTransferRequestMenu = 'StockTransferRequestMenu?id=' + id #RETURN VALUES HERE return dict(id=id, Name='StockTransferRequest', Label='Stock transfer request entry', Fields=fields, FieldsSrch=[Name], Read='StockTransferRequest', Add='StockTransferRequestSave', Del='StockTransferRequestDel', UnDel='StockTransferRequestUnDel', Edit='StockTransferRequest', Save='StockTransferRequestSave', SrchUrl='StockTransferRequestSearch', MenuBar=StockTransferRequestMenu)