tquoctuan97 / foody-api-nestjs

2 stars 0 forks source link

Add Adjustment List to Bill #19

Closed tquoctuan97 closed 3 weeks ago

tquoctuan97 commented 3 weeks ago

Adjustment List Documentation

Introduction

The adjustmentList is a feature of our billing system that allows for flexible application of additional fees and discounts to a bill. This document explains its purpose, structure, and usage.

Purpose of adjustmentList

Structure and Fields

This structure allows the user to manage and apply various fees and discounts to a bill.

Example

Here's an example of a complete bill structure using adjustmentList:

{
  "sum": 100,
  "adjustmentList": [
    { "name": "Service Fee", "type": "add", "amount": 50 },
    { "name": "Discount", "type": "subtract", "amount": 30 }
  ],
  "finalResult": 120
}

Calculation

To calculate the final result:

  1. Start with the original total (sum).
  2. Iterate through the adjustmentList:
    • For each item with type: "add", add the amount to the total.
    • For each item with type: "subtract", subtract the amount from the total.
let finalResult= sum;
for (let adjustment of adjustmentList) {
  if (adjustment.type === "add") {
    finalResult += adjustment.amount;
  } else if (adjustment.type === "subtract") {
    finalResult-= adjustment.amount;
  }
}

Migration Data

Currently, we have prepay and debt fields in the Bill document. After implementing the changes, we need to migrate the old data to the new adjustmentList structure.

Old

{
  "sum": 100,
  "prepay": 50,
  "debt": 30,
  "finalResult": 80
}

New

{
  "sum": 100,
  "adjustmentList": [
    { "name": "Prepay", "type": "subtract", "amount": 50 },
    { "name": "Debt", "type": "add", "amount": 30 }
  ],
  "finalResult": 80
}
tquoctuan97 commented 3 weeks ago

Migration Script

After running this script, all bills documents should have prePay and debt values moved into the adjustmentList, and the old fields should be kept for reference.

db.bills.aggregate([
  {
    $addFields: {
      adjustmentList: {
        $concatArrays: [
          { $ifNull: ['$adjustmentList', []] },
          {
            $filter: {
              input: [
                {
                  $cond: {
                    if: { $ne: ['$prePay', null] },
                    then: {
                      name: 'Prepay',
                      type: 'subtract',
                      amount: '$prePay',
                    },
                    else: null,
                  },
                },
                {
                  $cond: {
                    if: { $ne: ['$debt', null] },
                    then: {
                      name: 'Debt',
                      type: 'add',
                      amount: '$debt',
                    },
                    else: null,
                  },
                },
              ],
              as: 'item',
              cond: { $ne: ['$$item', null] },
            },
          },
        ],
      },
    },
  },
  {
    $merge: {
      into: 'bills',
      on: '_id',
      whenMatched: 'merge',
      whenNotMatched: 'discard',
    },
  },
]);

Let's break down this script:

  1. We use the aggregate pipeline for more complex operations:

    • $addFields: We're adding or modifying the adjustmentList field.
    • $concatArrays: We concatenate the existing adjustmentList (or an empty array if it doesn't exist) with new items.
    • $filter: We create new items only if prePay or debt are not null.
    • $cond: We use conditional operators to create the new adjustment items.
  2. The $merge stage writes the results back to the bills collection, updating existing documents.