I have a dictionary with a list , in the list there is also multiple dictionary value, please take a look below :
payment_data= {
'payment_details': [
{'name': 'X', 'to_pay': 9000, 'paid': False, 'date': '2021-09-28'},
{'name': 'X', 'to_pay': 8000, 'paid': False, 'date': '2021-09-27'},
{'name': 'X', 'to_pay': 6000, 'paid': False, 'date': '2021-09-26'},
{'name': 'X', 'to_pay': 5000, 'paid': False, 'date': '2021-09-25'},
{'name': 'X', 'to_pay': 3000, 'paid': False, 'date': '2021-09-24'},
{'name': 'X', 'to_pay': 2000, 'paid': False, 'date': '2021-09-23'}
]
}
What I want to do, I will take a input from a user of payment amount , if the user give 9000 , then first index of payment_details
where to_pay
key of dictionary will be 0 and paid
will be True
but the payment amount is greater than 9000 , suppose 19000 , in that case first index of payment_details
where to_pay
key of dictionary will be 0 and paid
will be also True
but it will minus the value from previous one(19000-9000=10000) and go to next index 1 , when index 1 value is 8000 , it will be 0 (because we have 10000) and paid will be True
and go to next index on an on. Sorry for my bad english. How can I do this in Python3?
CodePudding user response:
I think it will be better if the payment
can be made from the oldest to the most recent one. So, the 'payment_details'
may need to be sorted by date
first before performing subtraction.
Here's one of the ways
from operator import itemgetter
import json
payment_data = {
'payment_details': [
{'name': 'X', 'to_pay': 9000, 'paid': False, 'date': '2021-09-28'},
{'name': 'X', 'to_pay': 8000, 'paid': False, 'date': '2021-09-27'},
{'name': 'X', 'to_pay': 6000, 'paid': False, 'date': '2021-09-26'},
{'name': 'X', 'to_pay': 5000, 'paid': False, 'date': '2021-09-25'},
{'name': 'X', 'to_pay': 3000, 'paid': False, 'date': '2021-09-24'},
{'name': 'X', 'to_pay': 2000, 'paid': False, 'date': '2021-09-23'}
]
}
def make_payment(data: dict, payment: int) -> dict:
data['payment_details'] = sorted(data['payment_details'],
key=itemgetter('date'), reverse=False)
for detail in data['payment_details']:
if not detail['paid']:
detail['to_pay'] -= payment
if detail['to_pay'] <= 0:
payment = abs(detail['to_pay'])
detail['to_pay'] = 0
detail['paid'] = True
else:
payment = 0
break
return data
# test data
# first payment
payment_data = make_payment(payment_data, 12000)
print(json.dumps(payment_data, indent=2))
# second payment
payment_data = make_payment(payment_data, 7500)
print(json.dumps(payment_data, indent=2))
'payment_details'
after first payment (12000)
[
{'name': 'X', 'to_pay': 0, 'paid': True, 'date': '2021-09-23'},
{'name': 'X', 'to_pay': 0, 'paid': True, 'date': '2021-09-24'},
{'name': 'X', 'to_pay': 0, 'paid': True, 'date': '2021-09-25'},
{'name': 'X', 'to_pay': 4000, 'paid': False, 'date': '2021-09-26'},
{'name': 'X', 'to_pay': 8000, 'paid': False, 'date': '2021-09-27'},
{'name': 'X', 'to_pay': 9000, 'paid': False, 'date': '2021-09-28'},
]
'payment_details'
after second payment (7500)
[
{'name': 'X', 'to_pay': 0, 'paid': True, 'date': '2021-09-23'},
{'name': 'X', 'to_pay': 0, 'paid': True, 'date': '2021-09-24'},
{'name': 'X', 'to_pay': 0, 'paid': True, 'date': '2021-09-25'},
{'name': 'X', 'to_pay': 0, 'paid': True, 'date': '2021-09-26'},
{'name': 'X', 'to_pay': 4500, 'paid': False, 'date': '2021-09-27'},
{'name': 'X', 'to_pay': 9000, 'paid': False, 'date': '2021-09-28'},
]
CodePudding user response:
Assuming that payment_data["payment_details"]
is sorted by to_pay
in descending order, the following should work, at least the first time (because then the list might no longer be sorted by to_pay
).
payment_amount = 13000
for details in payment_data["payment_details"]:
if details["to_pay"] == payment_amount:
details["to_pay"] = 0
details["paid"] = True
break
else:
for details in payment_data["payment_details"]:
to_pay = details["to_pay"]
if payment_amount >= to_pay:
details["to_pay"] = 0
payment_amount -= to_pay
else:
details["to_pay"] -= payment_amount
break
You could probably break this into some functions to avoid repeating yourself. You might also think about the behavior in other scenarios, like in your example, what would happen in the user entered 4000?
CodePudding user response:
Here is a solution using the invoices sorted in ascending order of their payment due date:
from operator import itemgetter
def pay(payment_data, amount: int):
for detail in sorted(payment_data['payment_details'], key=itemgetter('date')):
if not detail['paid']:
to_pay = detail['to_pay']
payment_available = min(to_pay, amount)
balance = to_pay - payment_available
detail['to_pay'] = balance
if not balance:
detail['paid'] = True
amount -= payment_available
if not amount:
break
return payment_data
# Usage:
pay(payment_data, 10500)