def add_payment(sale, payment_opt): """ Add a payment to the specified sale """ db = current.db T = current.T add_new_payment = False # allow multiple payments for the same payment option if payment_opt.requires_account or common_utils.is_wallet( payment_opt) or sale.is_deferred: add_new_payment = True else: # get payments with the same payment option payment = db((db.payment.id_sale == sale.id) & (db.payment.id_payment_opt == payment_opt.id) & (db.payment.is_updatable == True)).select().first() if not payment: add_new_payment = True if add_new_payment: new_payment_id = db.payment.insert(id_payment_opt=payment_opt.id, id_sale=sale.id) return new_payment_id else: raise CP_PaymentError( T("You already have a payment with that payment option."))
def add_payment(sale, payment_opt): """ Add a payment to the specified sale """ db = current.db T = current.T add_new_payment = False # allow multiple payments for the same payment option if payment_opt.requires_account or common_utils.is_wallet(payment_opt) or sale.is_deferred: add_new_payment = True else: # get payments with the same payment option payment = db((db.payment.id_sale == sale.id) & (db.payment.id_payment_opt == payment_opt.id) & (db.payment.is_updatable == True) ).select().first() if not payment: add_new_payment = True if add_new_payment: new_payment_id = db.payment.insert(id_payment_opt=payment_opt.id, id_sale=sale.id) return new_payment_id else: raise CP_PaymentError( T("You already have a payment with that payment option.") )
def modify_payment(sale, payment, payment_data, delete=False): """ payment_data: { 'amount', 'wallet_code', 'account' } """ db = current.db T = current.T new_amount = payment_data.get('amount') # is wallet payment if payment.wallet_code: new_amount = payment.amount # delete payment if delete: new_amount = 0 # since calling this function, could cause modification to other payments, we have to store the modified payments, so the client can render the changes extra_updated_payments = [] total, change, payments = get_payments_data(sale.id) new_total = total - change - (payment.amount - payment.change_amount) + new_amount if new_total > (sale.total - sale.discount): # when the payment does not allow change, cut the amount to the exact remaining if not payment.id_payment_opt.allow_change: new_amount -= new_total - (sale.total - sale.discount) else: remaining = (sale.total - sale.discount) - new_total # when the payment modification makes the new total lower than the sale total, we have to find all the payments with change > 0 (if any) and recalculate their amount and their change for other_payment in payments: if not other_payment.id_payment_opt.allow_change or other_payment.id == payment.id: continue if remaining == 0: break if other_payment.change_amount > 0: new_remaining = min(remaining, other_payment.change_amount) new_change = other_payment.change_amount - new_remaining remaining -= new_remaining other_payment.change_amount = new_change other_payment.update_record() extra_updated_payments.append(other_payment) change = max(0, new_total - (sale.total - sale.discount)) account = payment_data.get('account') wallet_code = payment_data.get('wallet_code') # fix payment info if not payment.id_payment_opt.allow_change: change = 0 if not payment.id_payment_opt.requires_account: account = None if not common_utils.is_wallet(payment.id_payment_opt): wallet_code = None else: if payment.wallet_code: # return wallet funds, if the wallet payment is removed or the wallet code is changed if delete or wallet_code != payment.wallet_code: wallet = db( db.wallet.wallet_code == payment.wallet_code).select( for_update=True).first() if wallet: wallet.balance += payment.amount wallet.update_record() else: new_amount = 0 # only accept the first wallet code specified if wallet_code != payment.wallet_code: wallet = db(db.wallet.wallet_code == wallet_code).select( for_update=True).first() if wallet: new_amount = min(wallet.balance, (sale.total - sale.discount) - new_total) wallet.balance -= new_amount wallet.update_record() # if the code is invalid, remove its specified value else: wallet_code = None new_amount = 0 payment.amount = new_amount payment.change_amount = change payment.account = account payment.wallet_code = wallet_code payment.update_record() if not delete: extra_updated_payments.append(payment) elif payment.is_updatable: payment.delete_record() # get the total payments data payments_data = get_payments_data(sale.id) # amount - change_amount payments_total = payments_data[0] - payments_data[1] data = dict(payments_total=payments_total, updated_payments=extra_updated_payments) return data
def modify_payment(sale, payment, payment_data, delete=False): """ payment_data: { 'amount', 'wallet_code', 'account' } """ db = current.db T = current.T new_amount = payment_data.get('amount') # delete payment if delete: new_amount = 0 # since calling this function, could cause modification to other payments, we have to store the modified payments, so the client can render the changes extra_updated_payments = [] total, change, payments = get_payments_data(sale.id) new_total = total - change - (payment.amount - payment.change_amount) + new_amount if new_total > (sale.total - sale.discount): # when the payment does not allow change, cut the amount to the exact remaining if not payment.id_payment_opt.allow_change: new_amount -= new_total - (sale.total - sale.discount) else: remaining = (sale.total - sale.discount) - new_total # when the payment modification makes the new total lower than the sale total, we have to find all the payments with change > 0 (if any) and recalculate their amount and their change for other_payment in payments: if not other_payment.id_payment_opt.allow_change or other_payment.id == payment.id: continue if remaining == 0: break if other_payment.change_amount > 0: new_remaining = min(remaining, other_payment.change_amount) new_change = other_payment.change_amount - new_remaining remaining -= new_remaining other_payment.change_amount = new_change other_payment.update_record() extra_updated_payments.append(other_payment) change = max(0, new_total - (sale.total - sale.discount)) account = payment_data.get('account') wallet_code = payment_data.get('wallet_code') # fix payment info if not payment.id_payment_opt.allow_change: change = 0 if not payment.id_payment_opt.requires_account: account = None if not common_utils.is_wallet(payment.id_payment_opt): wallet_code = None # in this case the payment is wallet else: if payment.wallet_code: # return wallet funds, if the wallet payment is removed or the wallet code is changed if delete or wallet_code != payment.wallet_code: wallet_utils.transaction( payment.amount, wallet_utils.UNDO_PAYMENT, ref=payment.id, wallet_code=payment.wallet_code ) # only accept the first wallet code specified if wallet_code != payment.wallet_code: try: # new_amount = max(0, min(wallet.balance, (sale.total - sale.discount) - new_total)) rem_q = (sale.total - sale.discount) - new_total if rem_q >= 0: _wallet, _amount = wallet_utils.transaction( -rem_q, wallet_utils.CONCEPT_PAYMENT, ref=payment.id, wallet_code=wallet_code ) new_amount = abs(_amount) except: wallet_code = None new_amount = 0 payment.amount = new_amount payment.change_amount = change payment.account = account payment.wallet_code = wallet_code payment.update_record() if not delete: extra_updated_payments.append(payment) elif payment.is_updatable: payment.delete_record() # get the total payments data payments_data = get_payments_data(sale.id) # amount - change_amount payments_total = payments_data[0] - payments_data[1] data = dict( payments_total=payments_total, updated_payments=extra_updated_payments ) return data