Home > Enterprise >  Go to next index in list inside a python dictionary and perform calculation
Go to next index in list inside a python dictionary and perform calculation

Time:09-28

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)
  • Related