Skip to content
This repository has been archived by the owner on Nov 8, 2024. It is now read-only.

(feat) HSC-306: ERP billing status via widget #1

Merged
merged 25 commits into from
Nov 6, 2024
Merged

Conversation

usamaidrsk
Copy link
Member

@usamaidrsk usamaidrsk commented Oct 7, 2024

Requirements

  • This PR has a title that briefly describes the work done including a conventional commit type prefix and a Jira ticket number if applicable. See existing PR titles for inspiration.

For changes to apps

If applicable

  • My work includes tests or is validated by existing tests.

Summary

Description

This PR introduces a comprehensive configuration schema for the patient billing status module, providing flexible control over billing line conditions and system field mappings.

Key Changes

  1. Introduced strongly-typed billing conditions with the following states:

    • Order status (ORDER)
    • Invoice status (INVOICED, NOT_INVOICED, FULLY_INVOICED, PARTIALLY_INVOICED)
    • Payment status (PAID, NOT_PAID)
    • Due date status (OVERDUE, NOT_OVERDUE)
    • Cancellation status (CANCELLED)
  2. Added configuration options for:

    • Retire conditions: Define when billing lines should be removed from view
    • Approval conditions: Specify combinations of states that indicate approved billing
    • Non-approval conditions: Define state combinations that indicate pending/problematic billing
    • Field mapping: Configure system field names for patient UUID and external order ID
  3. Implemented validation logic to prevent conflicting condition states, such as:

    • INVOICED vs NOT_INVOICED
    • FULLY_INVOICED vs PARTIALLY_INVOICED
    • PAID vs NOT_PAID
    • OVERDUE vs NOT_OVERDUE

Configuration Example

{
  // Remove cancelled orders and fully invoiced orders from view
  retireLinesConditions: ['CANCELLED', 'ORDER,FULLY_INVOICED'],
  
  // Define non-approved states
  nonApprovedConditions: [
    'INVOICED,NOT_PAID',
    'ORDER,NOT_INVOICED',
    'INVOICED,OVERDUE,NOT_PAID'
  ],
  
  // Define approved states
  approvedConditions: [
    'INVOICED,PAID',
    'INVOICED,NOT_OVERDUE',
    'INVOICED,NOT_OVERDUE,PAID'
  ],
  
  // System field mappings
  patientUuidFieldName: 'partner_id',
  orderExternalIdFieldName: 'external_order_id'
}

Screenshots

image
image
image

Related Issue

https://mekomsolutions.atlassian.net/issues/HSC-306?filter=-1

Other

@usamaidrsk usamaidrsk self-assigned this Oct 7, 2024
@rbuisson
Copy link
Member

Thank you for the great documentation on PR description, make sure this is shown in the README too.
What's the behavior for grouping the orders? Is it per day?

(One cosmetic change: could you use the "outline" icons instead of "filled"?)

@usamaidrsk usamaidrsk closed this Oct 29, 2024
@usamaidrsk usamaidrsk reopened this Oct 29, 2024
@usamaidrsk
Copy link
Member Author

What's the behavior for grouping the orders? Is it per day?

Yes @rbuisson, grouping is by day.

@usamaidrsk
Copy link
Member Author

(One cosmetic change: could you use the "outline" icons instead of "filled"?)

Hi @rbuisson
I have update the readme and used the outlined icons

Copy link
Member

@rbuisson rbuisson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I let it to @vasharma05 to provide final approval.

Copy link
Member

@vasharma05 vasharma05 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of comments for re-checking and a few suggestions. Missed out on translations too, but I am happy to see the great effort you put into this, great work @usamaidrsk 👏

@@ -52,7 +52,7 @@ jobs:

- name: Stop dev server
if: "!cancelled()"
run: docker stop $(docker ps -a -q)
run: docker stop $(docker ps -a -q | xargs -r docker stop)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you add this referencing somewhere else?

orderExternalIdFieldName: 'external_order_id'
}
}
```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing 👏

@@ -53,6 +54,7 @@
},
"devDependencies": {
"@openmrs/esm-framework": "next",
"@openmrs/esm-patient-common-lib": "next",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@usamaidrsk, do bump the framework and common lib in this PR again. Thanks!

package.json Outdated Show resolved Hide resolved
Comment on lines 42 to 43
const isTablet = layout === 'tablet';
const isDesktop = layout === 'small-desktop' || layout === 'large-desktop';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we don't support phone layout, we can assume that isDesktop = !isTablet

src/resources/billing-status.resource.ts Outdated Show resolved Hide resolved
Comment on lines 271 to 276
const [orders, invoices] = await Promise.all([
fetchOrders(patientUuid, config),
fetchInvoices(patientUuid, config),
// TODO fetch patient visits fetchVisits(patientUuid)
]);
return processBillingLines(orders, invoices, config);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do all of this using SWR too, let's use SWR for data fetching.

You can write SWR hooks for each fetching, and final billingLines will be calculated/ processed once all the data is present. All these requests will go parallel in this scenario too, and you don't have to handle promises

return response.data;
};

const fetchInvoices = async (patientUuid: string, config: Config) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fetch all these using SWR, have added a suggestion elsewhere.

<Resources />
</div>
);
return <div>root</div>;
};

export default Root;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove this file altogether, if we are not using this

expect(screen.getByRole('heading', { name: /data fetching/i })).toBeInTheDocument();
expect(screen.getByRole('heading', { name: /resources/i })).toBeInTheDocument();
expect(screen.getByRole('button', { name: /get a patient named 'test'/i })).toBeInTheDocument();
expect(screen.getByText('root')).toBeInTheDocument();
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file too

@usamaidrsk usamaidrsk requested a review from vasharma05 November 6, 2024 06:17
Copy link
Member

@vasharma05 vasharma05 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few changes, else good to go!
Thanks @usamaidrsk for the great work!

src/index.ts Outdated
export const blueBox = getAsyncLifecycle(() => import('./boxes/extensions/blue-box.component'), options);

export const brandBox = getAsyncLifecycle(() => import('./boxes/extensions/brand-box.component'), options);
export const patientBillingStatusOverview = getSyncLifecycle(patientBillingStatusSummary, options);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be async. The only items meant to be sync are the dashboard links and icon buttons which navigate to other pages.

Comment on lines +33 to +34
startDate: visit.startDatetime,
endDate: visit.stopDatetime,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we need to use the order's datetime it was placed and the endDatetime?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we fetching all the visits?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes we do need all visits to group the orders in each visit. Though this is not working at he moment, I just left the code if we intend to group by visits someday

tags.push(BillingCondition.NOT_OVERDUE);
}

let orderId = ''; // TODO this should be the orderExternalId of the invoice order
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this TODO still pending?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it is still pending

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants