Skip to content

feat: epic invoicing phase 2#9044

Merged
chris-bes merged 31 commits intomainfrom
epic-invoicing-phase-2
Mar 5, 2026
Merged

feat: epic invoicing phase 2#9044
chris-bes merged 31 commits intomainfrom
epic-invoicing-phase-2

Conversation

@tcaiger
Copy link
Copy Markdown
Contributor

@tcaiger tcaiger commented Jan 22, 2026

Changes

Add a brief description of the changes in this PR to help give the reviewer context.

Deploys

  • Deploy to Tamanu Internal

Tests

  • Run E2E Tests

Remember to...

  • ...write or update tests
  • ...add UI screenshots and testing notes to the Linear issue
  • ...add any manual upgrade steps to the Linear issue
  • ...update the config reference, settings reference, or any relevant runbook(s)
  • ...call out additions or changes to config files for the deployment team to take note of

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @tcaiger, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request delivers 'Epic Invoicing Phase 2', a comprehensive upgrade to the invoicing system. It introduces a more robust and granular data model for managing insurance coverage, allowing for multiple insurance plans per invoice and immutable finalized coverage values per item. The system now automates the creation and modification of invoice items based on clinical activities like procedures, lab requests, and imaging requests, streamlining the billing workflow. Significant updates to the API and user interface reflect these changes, providing a more accurate, flexible, and automated invoicing experience.

Highlights

  • Insurance Model Refactor: The previous invoice_insurers table has been replaced by a new many-to-many junction table, invoices_invoice_insurance_plans, linking invoices to insurance contracts. Additionally, invoice_item_finalised_insurances has been introduced to store immutable coverage values per invoice item, ensuring historical accuracy.
  • Invoice Item Enhancements: Invoice items now include fields for product_name_final, product_code_final, price_final, and manual_entry_price to capture finalized product details and allow for manual price overrides. A new approved status has also been added to individual invoice line items.
  • Automated Invoice Item Creation: The system now automatically adds or removes invoice items based on the lifecycle and status changes of Procedure, LabRequest, and ImagingRequest records. This automation is configurable via new settings, including specific statuses that trigger invoicing and exclusions for certain encounter types.
  • Price List Item Visibility: A new is_hidden field has been added to invoice_price_list_items, allowing administrators to control whether a product is visible in frontend searches and automatically added to invoices.
  • Invoice Finalization Process: The invoice finalization process has been enhanced to freeze all relevant product details (name, code, price) directly onto the invoice item and to record the insurance coverage values in the new invoice_item_finalised_insurances table, preserving the state at the time of finalization.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a major refactoring of the invoicing system, overhauling the data model for insurance to be more granular at the item level, and introducing automated processes for invoice creation and item management. Key changes include replacing the invoice_insurers table, adding finalization logic to invoice items, and implementing model hooks for automatic item addition/removal. The UI has also seen significant refactoring. My feedback focuses on improving documentation clarity, ensuring migration safety, and enhancing user experience through clearer UI text and error messages. Overall, this is a substantial and well-structured update.

Comment on lines +14 to +16
await query.addColumn('invoice_products', 'discountable', {
type: DataTypes.BOOLEAN,
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

The down function re-adds the discountable column but is missing allowNull: false and a defaultValue. The original schema for discountable in invoice_products.yml had a not_null data test, and the up function for the new insurable column correctly includes these properties. This omission could cause issues if the migration is rolled back on a table with existing data.

  await query.addColumn('invoice_products', 'discountable', {
    type: DataTypes.BOOLEAN,
    allowNull: false,
    defaultValue: true,
  });

{% enddocs %}

{% docs invoice_products__insurable %}
Whether or not discounts can be applied to a product
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The description for insurable appears to be a copy-paste from the old discountable field. It should be updated to accurately describe what insurable means in the context of an invoice product, which is whether it can be covered by an insurance plan.

Suggested change
Whether or not discounts can be applied to a product
Whether or not this product can be covered by an insurance plan.

Comment on lines 378 to 380
throw new InvalidOperationError(
'Ivnvoice cannot be finalised until the Encounter has been closed',
'Invoice cannot be finalised until the encounter has been discharged',
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The error message '...until the encounter has been discharged' is a bit specific. The logic checks for encounter.endDate. An encounter can be closed for reasons other than discharge (e.g., patient death). Using the term 'closed' would be more generic and accurate, aligning better with the code's logic.

Suggested change
throw new InvalidOperationError(
'Ivnvoice cannot be finalised until the Encounter has been closed',
'Invoice cannot be finalised until the encounter has been discharged',
);
throw new InvalidOperationError(
'Invoice cannot be finalised until the encounter has been closed',
);

export const CodeCell = ({ item, isItemEditable }) => {
let productCode = item.productCodeFinal || item.productCode || null;
if (!isItemEditable && !productCode) {
productCode = 'N/A';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Using 'N/A' for an empty product code might be ambiguous to users, as it could imply 'Not Applicable' when the value is simply missing. Using a hyphen ('-') is a more common and clearer convention for representing empty or unavailable data in a table.

Suggested change
productCode = 'N/A';
productCode = '-';

@tcaiger tcaiger changed the title Epic invoicing phase 2 feat: epic invoicing phase 2 Jan 22, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jan 22, 2026

🍹 up on tamanu-on-k8s/bes/tamanu-on-k8s/epic-invoicing-phase-2

Pulumi report
   Updating (epic-invoicing-phase-2)

View Live: https://app.pulumi.com/bes/tamanu-on-k8s/epic-invoicing-phase-2/updates/28

Downloading plugin random-4.19.0: starting
Downloading plugin random-4.19.0: done
Installing plugin random-4.19.0: starting
Installing plugin random-4.19.0: done

@ Updating....
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running 
@ Updating....
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running read kubernetes:core/v1:Namespace tamanu-epic-invoicing-phase-2
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running read pulumi:pulumi:StackReference bes/k8s-core/tamanu-internal-main
@ Updating....
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running read pulumi:pulumi:StackReference bes/k8s-core/tamanu-internal-main
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running Using tailscale proxy https://k8s-operator-tamanu-internal-main.tail53aef.ts.net
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running read pulumi:pulumi:StackReference bes/core/tamanu-internal
@ Updating....
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running read pulumi:pulumi:StackReference bes/core/tamanu-internal
@ Updating....
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running read kubernetes:core/v1:Namespace tamanu-epic-invoicing-phase-2
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running Waiting for central-db...
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running Waiting for facility-1-db...
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running Waiting for facility-2-db...
@ Updating....
~  kubernetes:apps/v1:Deployment facility-1-web updating (0s) [diff: ~spec]
~  kubernetes:apps/v1:Deployment facility-2-web updating (0s) [diff: ~spec]
~  kubernetes:apps/v1:Deployment patient-portal-web updating (0s) [diff: ~spec]
~  kubernetes:apps/v1:Deployment central-web updating (0s) [diff: ~spec]
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running read kubernetes:core/v1:ConfigMap actual-provisioning
++ kubernetes:batch/v1:Job central-migrator creating replacement (0s) [diff: ~spec]
@ Updating....
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running Secret central-db-superuser not found or not ready: Error: HTTP-Code: 404
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running Message: Unknown API Status Code!
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running Body: "{\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"secrets \\\"central-db-superuser\\\" not found\",\"reason\":\"NotFound\",\"details\":{\"name\":\"central-db-superuser\",\"kind\":\"secrets\"},\"code\":404}
"
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running Headers: {"audit-id":"00d70db4-b7e1-4b88-a36b-b2fb08487841","cache-control":"no-cache, private","connection":"close","content-length":"214","content-type":"application/json","date":"Mon, 02 Mar 2026 05:18:48 GMT","x-kubernetes-pf-flowschema-uid":"3fb296fc-e46b-45d1-9306-057e37ddd229","x-kubernetes-pf-prioritylevel-uid":"feccf24d-a074-4fa8-aa6f-db82477fc2f5"}
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running Secret facility-2-db-superuser not found or not ready: Error: HTTP-Code: 404
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running Message: Unknown API Status Code!
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running Body: "{\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"secrets \\\"facility-2-db-superuser\\\" not found\",\"reason\":\"NotFound\",\"details\":{\"name\":\"facility-2-db-superuser\",\"kind\":\"secrets\"},\"code\":404}
"
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running Headers: {"audit-id":"5ce04072-2540-464f-bcc7-edf05a2a925c","cache-control":"no-cache, private","connection":"close","content-length":"220","content-type":"application/json","date":"Mon, 02 Mar 2026 05:18:48 GMT","x-kubernetes-pf-flowschema-uid":"3fb296fc-e46b-45d1-9306-057e37ddd229","x-kubernetes-pf-prioritylevel-uid":"feccf24d-a074-4fa8-aa6f-db82477fc2f5"}
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running Secret facility-1-db-superuser not found or not ready: Error: HTTP-Code: 404
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running Message: Unknown API Status Code!
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running Body: "{\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"secrets \\\"facility-1-db-superuser\\\" not found\",\"reason\":\"NotFound\",\"details\":{\"name\":\"facility-1-db-superuser\",\"kind\":\"secrets\"},\"code\":404}
"
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running Headers: {"audit-id":"a0c88c6a-6a31-48d4-b93a-0edef2bd4d58","cache-control":"no-cache, private","connection":"close","content-length":"220","content-type":"application/json","date":"Mon, 02 Mar 2026 05:18:48 GMT","x-kubernetes-pf-flowschema-uid":"3fb296fc-e46b-45d1-9306-057e37ddd229","x-kubernetes-pf-prioritylevel-uid":"feccf24d-a074-4fa8-aa6f-db82477fc2f5"}
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2 running read kubernetes:core/v1:ConfigMap actual-provisioning
++ kubernetes:batch/v1:Job central-migrator creating replacement (1s) [diff: ~spec]; 
@ Updating....
++ kubernetes:batch/v1:Job facility-1-migrator creating replacement (0s) [diff: ~spec]
++ kubernetes:batch/v1:Job facility-2-migrator creating replacement (0s) [diff: ~spec]
++ kubernetes:batch/v1:Job central-migrator creating replacement (2s) [diff: ~spec]; Waiting for Job "tamanu-epic-invoicing-phase-2/central-migrator-a9287381" to start
++ kubernetes:batch/v1:Job central-migrator creating replacement (2s) [diff: ~spec]; Waiting for Job "tamanu-epic-invoicing-phase-2/central-migrator-a9287381" to succeed (Active: 1 | Succeeded: 0 | Failed: 0)
@ Updating....
~  kubernetes:apps/v1:Deployment patient-portal-web updating (2s) [diff: ~spec]; Waiting for app ReplicaSet to be available (0/1 Pods available)
~  kubernetes:apps/v1:Deployment facility-1-web updating (3s) [diff: ~spec]; Waiting for app ReplicaSet to be available (0/1 Pods available)
~  kubernetes:apps/v1:Deployment facility-2-web updating (3s) [diff: ~spec]; Waiting for app ReplicaSet to be available (0/1 Pods available)
~  kubernetes:apps/v1:Deployment central-web updating (2s) [diff: ~spec]; Waiting for app ReplicaSet to be available (0/1 Pods available)
++ kubernetes:batch/v1:Job facility-1-migrator creating replacement (0s) [diff: ~spec]; 
++ kubernetes:batch/v1:Job facility-1-migrator creating replacement (0s) [diff: ~spec]; Waiting for Job "tamanu-epic-invoicing-phase-2/facility-1-migrator-d3f6ff11" to start
++ kubernetes:batch/v1:Job facility-2-migrator creating replacement (0s) [diff: ~spec]; 
++ kubernetes:batch/v1:Job facility-1-migrator creating replacement (0s) [diff: ~spec]; Waiting for Job "tamanu-epic-invoicing-phase-2/facility-1-migrator-d3f6ff11" to succeed (Active: 1 | Succeeded: 0 | Failed: 0)
++ kubernetes:batch/v1:Job facility-2-migrator creating replacement (0s) [diff: ~spec]; Waiting for Job "tamanu-epic-invoicing-phase-2/facility-2-migrator-836ad37a" to start
++ kubernetes:batch/v1:Job facility-2-migrator creating replacement (0s) [diff: ~spec]; Waiting for Job "tamanu-epic-invoicing-phase-2/facility-2-migrator-836ad37a" to succeed (Active: 1 | Succeeded: 0 | Failed: 0)
@ Updating.............
~  kubernetes:apps/v1:Deployment facility-1-web updating (13s) [diff: ~spec]; warning: [Pod tamanu-epic-invoicing-phase-2/facility-1-web-98cc218f-76f497cd98-lmz6f]: containers with unready status: [http]
~  kubernetes:apps/v1:Deployment facility-2-web updating (13s) [diff: ~spec]; warning: [Pod tamanu-epic-invoicing-phase-2/facility-2-web-4b947a20-785999dd47-ds74f]: containers with unready status: [http]
~  kubernetes:apps/v1:Deployment central-web updating (12s) [diff: ~spec]; warning: [Pod tamanu-epic-invoicing-phase-2/central-web-297ec79d-f756f949b-zzfxf]: containers with unready status: [http]
@ Updating....
~  kubernetes:apps/v1:Deployment central-web updating (14s) [diff: ~spec]; Waiting for app ReplicaSet to be available (1/2 Pods available)
~  kubernetes:apps/v1:Deployment facility-1-web updating (14s) [diff: ~spec]; Waiting for app ReplicaSet to be available (1/2 Pods available)
@ Updating.....
~  kubernetes:apps/v1:Deployment facility-2-web updating (16s) [diff: ~spec]; Waiting for app ReplicaSet to be available (1/2 Pods available)
@ Updating........
++ kubernetes:batch/v1:Job facility-1-migrator creating replacement (19s) [diff: ~spec]; warning: [Pod tamanu-epic-invoicing-phase-2/facility-1-migrator-d3f6ff11-n22bp]: Container "migrator" completed with exit code 0
@ Updating....
++ kubernetes:batch/v1:Job facility-2-migrator creating replacement (19s) [diff: ~spec]; warning: [Pod tamanu-epic-invoicing-phase-2/facility-2-migrator-836ad37a-zn2kx]: Container "migrator" completed with exit code 0
@ Updating....
~  kubernetes:apps/v1:Deployment facility-1-web updating (23s) [diff: ~spec]; warning: [Pod tamanu-epic-invoicing-phase-2/facility-1-web-98cc218f-76f497cd98-pcp2w]: containers with unready status: [http]
~  kubernetes:apps/v1:Deployment facility-2-web updating (23s) [diff: ~spec]; warning: [Pod tamanu-epic-invoicing-phase-2/facility-2-web-4b947a20-785999dd47-dntgl]: containers with unready status: [http]
~  kubernetes:apps/v1:Deployment central-web updating (22s) [diff: ~spec]; warning: [Pod tamanu-epic-invoicing-phase-2/central-web-297ec79d-f756f949b-m86ns]: containers with unready status: [http]
++ kubernetes:batch/v1:Job facility-1-migrator creating replacement (21s) [diff: ~spec]; Waiting for Job "tamanu-epic-invoicing-phase-2/facility-1-migrator-d3f6ff11" to succeed (Active: 0 | Succeeded: 0 | Failed: 0)
@ Updating....
++ kubernetes:batch/v1:Job facility-2-migrator creating replacement (21s) [diff: ~spec]; Waiting for Job "tamanu-epic-invoicing-phase-2/facility-2-migrator-836ad37a" to succeed (Active: 0 | Succeeded: 0 | Failed: 0)
++ kubernetes:batch/v1:Job facility-1-migrator creating replacement (21s) [diff: ~spec]; Waiting for Job "tamanu-epic-invoicing-phase-2/facility-1-migrator-d3f6ff11" to succeed (Active: 0 | Succeeded: 1 | Failed: 0)
++ kubernetes:batch/v1:Job facility-1-migrator creating replacement (21s) [diff: ~spec]; 
++ kubernetes:batch/v1:Job facility-2-migrator creating replacement (21s) [diff: ~spec]; Waiting for Job "tamanu-epic-invoicing-phase-2/facility-2-migrator-836ad37a" to succeed (Active: 0 | Succeeded: 1 | Failed: 0)
++ kubernetes:batch/v1:Job facility-1-migrator created replacement (21s) [diff: ~spec]; 
++ kubernetes:batch/v1:Job facility-2-migrator creating replacement (21s) [diff: ~spec]; 
++ kubernetes:batch/v1:Job facility-2-migrator created replacement (21s) [diff: ~spec]; 
+- kubernetes:batch/v1:Job facility-1-migrator replacing (0s) [diff: ~spec]; 
+- kubernetes:batch/v1:Job facility-1-migrator replaced (0.00s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment facility-1-sync updating (0s) [diff: ~spec]
~  kubernetes:apps/v1:Deployment facility-1-api updating (0s) [diff: ~spec]
~  kubernetes:apps/v1:Deployment facility-1-tasks updating (0s) [diff: ~spec]
+- kubernetes:batch/v1:Job facility-2-migrator replacing (0s) [diff: ~spec]; 
+- kubernetes:batch/v1:Job facility-2-migrator replaced (0.00s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment facility-2-tasks updating (0s) [diff: ~spec]
~  kubernetes:apps/v1:Deployment facility-2-api updating (0s) [diff: ~spec]
~  kubernetes:apps/v1:Deployment facility-2-sync updating (0s) [diff: ~spec]
++ kubernetes:batch/v1:Job central-migrator creating replacement (24s) [diff: ~spec]; warning: [Pod tamanu-epic-invoicing-phase-2/central-migrator-a9287381-75jcx]: Container "migrator" completed with exit code 0
~  kubernetes:apps/v1:Deployment facility-1-web updating (24s) [diff: ~spec]; Deployment initialization complete
~  kubernetes:apps/v1:Deployment facility-1-web updating (24s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment facility-1-web updated (24s) [diff: ~spec]; 
@ Updating.....
~  kubernetes:apps/v1:Deployment facility-1-sync updating (2s) [diff: ~spec]; Deployment initialization complete
~  kubernetes:apps/v1:Deployment facility-1-sync updating (2s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment facility-1-sync updated (2s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment central-web updating (25s) [diff: ~spec]; Deployment initialization complete
~  kubernetes:apps/v1:Deployment central-web updating (25s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment central-web updated (25s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment facility-1-api updating (2s) [diff: ~spec]; Deployment initialization complete
~  kubernetes:apps/v1:Deployment facility-1-api updating (2s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment facility-1-api updated (2s) [diff: ~spec]; 
@ Updating....
++ kubernetes:batch/v1:Job central-migrator creating replacement (26s) [diff: ~spec]; Waiting for Job "tamanu-epic-invoicing-phase-2/central-migrator-a9287381" to succeed (Active: 0 | Succeeded: 0 | Failed: 0)
++ kubernetes:batch/v1:Job central-migrator creating replacement (26s) [diff: ~spec]; Waiting for Job "tamanu-epic-invoicing-phase-2/central-migrator-a9287381" to succeed (Active: 0 | Succeeded: 1 | Failed: 0)
++ kubernetes:batch/v1:Job central-migrator creating replacement (26s) [diff: ~spec]; 
++ kubernetes:batch/v1:Job central-migrator created replacement (26s) [diff: ~spec]; 
+- kubernetes:batch/v1:Job central-migrator replacing (0s) [diff: ~spec]; 
+- kubernetes:batch/v1:Job central-migrator replaced (0.00s) [diff: ~spec]; 
++ kubernetes:batch/v1:Job central-provisioner creating replacement (0s) [diff: ~spec]
@ Updating....
++ kubernetes:batch/v1:Job central-provisioner creating replacement (0s) [diff: ~spec]; 
++ kubernetes:batch/v1:Job central-provisioner creating replacement (0s) [diff: ~spec]; Waiting for Job "tamanu-epic-invoicing-phase-2/central-provisioner-8eb2475b" to start
++ kubernetes:batch/v1:Job central-provisioner creating replacement (0s) [diff: ~spec]; Waiting for Job "tamanu-epic-invoicing-phase-2/central-provisioner-8eb2475b" to succeed (Active: 1 | Succeeded: 0 | Failed: 0)
~  kubernetes:apps/v1:Deployment facility-1-tasks updating (4s) [diff: ~spec]; warning: Replicas scaled to 0 for Deployment "facility-1-tasks-2822add8"
~  kubernetes:apps/v1:Deployment facility-1-tasks updating (4s) [diff: ~spec]; Deployment initialization complete
~  kubernetes:apps/v1:Deployment facility-1-tasks updating (4s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment facility-1-tasks updated (4s) [diff: ~spec]; 
@ Updating....
~  kubernetes:apps/v1:Deployment facility-2-tasks updating (4s) [diff: ~spec]; warning: Replicas scaled to 0 for Deployment "facility-2-tasks-fa131af3"
~  kubernetes:apps/v1:Deployment facility-2-tasks updating (4s) [diff: ~spec]; Deployment initialization complete
~  kubernetes:apps/v1:Deployment facility-2-tasks updating (4s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment facility-2-tasks updated (4s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment facility-2-api updating (5s) [diff: ~spec]; Deployment initialization complete
~  kubernetes:apps/v1:Deployment facility-2-api updating (5s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment facility-2-api updated (5s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment facility-2-sync updating (5s) [diff: ~spec]; warning: Replicas scaled to 0 for Deployment "facility-2-sync"
~  kubernetes:apps/v1:Deployment facility-2-sync updating (5s) [diff: ~spec]; Deployment initialization complete
~  kubernetes:apps/v1:Deployment facility-2-sync updating (5s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment facility-2-sync updated (5s) [diff: ~spec]; 
@ Updating....
~  kubernetes:apps/v1:Deployment facility-2-web updating (30s) [diff: ~spec]; Deployment initialization complete
~  kubernetes:apps/v1:Deployment facility-2-web updating (30s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment facility-2-web updated (30s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment patient-portal-web updating (30s) [diff: ~spec]; Deployment initialization complete
~  kubernetes:apps/v1:Deployment patient-portal-web updating (30s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment patient-portal-web updated (30s) [diff: ~spec]; 
@ Updating.................
++ kubernetes:batch/v1:Job central-provisioner creating replacement (17s) [diff: ~spec]; warning: [Pod tamanu-epic-invoicing-phase-2/central-provisioner-8eb2475b-fn99t]: Container "provisioner" completed with exit code 0
@ Updating....
++ kubernetes:batch/v1:Job central-provisioner creating replacement (17s) [diff: ~spec]; Waiting for Job "tamanu-epic-invoicing-phase-2/central-provisioner-8eb2475b" to succeed (Active: 0 | Succeeded: 0 | Failed: 0)
++ kubernetes:batch/v1:Job central-provisioner creating replacement (18s) [diff: ~spec]; Waiting for Job "tamanu-epic-invoicing-phase-2/central-provisioner-8eb2475b" to succeed (Active: 0 | Succeeded: 1 | Failed: 0)
++ kubernetes:batch/v1:Job central-provisioner creating replacement (18s) [diff: ~spec]; 
++ kubernetes:batch/v1:Job central-provisioner created replacement (18s) [diff: ~spec]; 
+- kubernetes:batch/v1:Job central-provisioner replacing (0s) [diff: ~spec]; 
+- kubernetes:batch/v1:Job central-provisioner replaced (0.00s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment central-fhir-resolver updating (0s) [diff: ~spec]
~  kubernetes:apps/v1:Deployment central-tasks updating (0s) [diff: ~spec]
@ Updating....
~  kubernetes:apps/v1:Deployment central-api updating (0s) [diff: ~spec]
~  kubernetes:apps/v1:Deployment central-fhir-refresh updating (0s) [diff: ~spec]
@ Updating.....
~  kubernetes:apps/v1:Deployment central-fhir-resolver updating (2s) [diff: ~spec]; Waiting for app ReplicaSet to be available (0/1 Pods available)
~  kubernetes:apps/v1:Deployment central-tasks updating (2s) [diff: ~spec]; Deployment initialization complete
~  kubernetes:apps/v1:Deployment central-tasks updating (2s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment central-tasks updated (2s) [diff: ~spec]; 
@ Updating....
~  kubernetes:apps/v1:Deployment central-api updating (3s) [diff: ~spec]; Deployment initialization complete
~  kubernetes:apps/v1:Deployment central-api updating (3s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment central-fhir-refresh updating (3s) [diff: ~spec]; Deployment initialization complete
~  kubernetes:apps/v1:Deployment central-fhir-refresh updating (3s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment central-fhir-refresh updated (3s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment central-api updated (3s) [diff: ~spec]; 
@ Updating....
~  kubernetes:apps/v1:Deployment central-fhir-resolver updating (4s) [diff: ~spec]; Deployment initialization complete
~  kubernetes:apps/v1:Deployment central-fhir-resolver updating (4s) [diff: ~spec]; 
~  kubernetes:apps/v1:Deployment central-fhir-resolver updated (4s) [diff: ~spec]; 
@ Updating....
-- kubernetes:batch/v1:Job central-provisioner deleting original (0s) [diff: ~spec]; 
-- kubernetes:batch/v1:Job central-provisioner deleting original (0s) [diff: ~spec]; 
-- kubernetes:batch/v1:Job central-provisioner deleted original (0.69s) [diff: ~spec]; 
-- kubernetes:batch/v1:Job central-migrator deleting original (0s) [diff: ~spec]; 
-- kubernetes:batch/v1:Job facility-2-migrator deleting original (0s) [diff: ~spec]; 
-- kubernetes:batch/v1:Job facility-1-migrator deleting original (0s) [diff: ~spec]; 
@ Updating....
-- kubernetes:batch/v1:Job central-migrator deleting original (0s) [diff: ~spec]; 
-- kubernetes:batch/v1:Job central-migrator deleted original (0.54s) [diff: ~spec]; 
@ Updating....
-- kubernetes:batch/v1:Job facility-2-migrator deleting original (1s) [diff: ~spec]; 
-- kubernetes:batch/v1:Job facility-2-migrator deleted original (1s) [diff: ~spec]; 
-- kubernetes:batch/v1:Job facility-1-migrator deleting original (1s) [diff: ~spec]; 
-- kubernetes:batch/v1:Job facility-1-migrator deleted original (1s) [diff: ~spec]; 
   pulumi:pulumi:Stack tamanu-on-k8s-epic-invoicing-phase-2  16 messages
Diagnostics:
 pulumi:pulumi:Stack (tamanu-on-k8s-epic-invoicing-phase-2):
   Waiting for central-db...
   Waiting for facility-1-db...
   Waiting for facility-2-db...

   Using tailscale proxy https://k8s-operator-tamanu-internal-main.tail53aef.ts.net

   Secret central-db-superuser not found or not ready: Error: HTTP-Code: 404
   Message: Unknown API Status Code!
   Body: "{\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"secrets \\\"central-db-superuser\\\" not found\",\"reason\":\"NotFound\",\"details\":{\"name\":\"central-db-superuser\",\"kind\":\"secrets\"},\"code\":404}
"
   Headers: {"audit-id":"00d70db4-b7e1-4b88-a36b-b2fb08487841","cache-control":"no-cache, private","connection":"close","content-length":"214","content-type":"application/json","date":"Mon, 02 Mar 2026 05:18:48 GMT","x-kubernetes-pf-flowschema-uid":"3fb296fc-e46b-45d1-9306-057e37ddd229","x-kubernetes-pf-prioritylevel-uid":"feccf24d-a074-4fa8-aa6f-db82477fc2f5"}
   Secret facility-2-db-superuser not found or not ready: Error: HTTP-Code: 404
   Message: Unknown API Status Code!
   Body: "{\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"secrets \\\"facility-2-db-superuser\\\" not found\",\"reason\":\"NotFound\",\"details\":{\"name\":\"facility-2-db-superuser\",\"kind\":\"secrets\"},\"code\":404}
"
   Headers: {"audit-id":"5ce04072-2540-464f-bcc7-edf05a2a925c","cache-control":"no-cache, private","connection":"close","content-length":"220","content-type":"application/json","date":"Mon, 02 Mar 2026 05:18:48 GMT","x-kubernetes-pf-flowschema-uid":"3fb296fc-e46b-45d1-9306-057e37ddd229","x-kubernetes-pf-prioritylevel-uid":"feccf24d-a074-4fa8-aa6f-db82477fc2f5"}
   Secret facility-1-db-superuser not found or not ready: Error: HTTP-Code: 404
   Message: Unknown API Status Code!
   Body: "{\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"secrets \\\"facility-1-db-superuser\\\" not found\",\"reason\":\"NotFound\",\"details\":{\"name\":\"facility-1-db-superuser\",\"kind\":\"secrets\"},\"code\":404}
"
   Headers: {"audit-id":"a0c88c6a-6a31-48d4-b93a-0edef2bd4d58","cache-control":"no-cache, private","connection":"close","content-length":"220","content-type":"application/json","date":"Mon, 02 Mar 2026 05:18:48 GMT","x-kubernetes-pf-flowschema-uid":"3fb296fc-e46b-45d1-9306-057e37ddd229","x-kubernetes-pf-prioritylevel-uid":"feccf24d-a074-4fa8-aa6f-db82477fc2f5"}

   [Pulumi Neo] Would you like help with these diagnostics?
   https://app.pulumi.com/bes/tamanu-on-k8s/epic-invoicing-phase-2/updates/28?explainFailure

Outputs:
   urls: {
       Central      : "https://central.epic-invoicing-phase-2.cd.tamanu.app"
       Facility- 1  : "https://facility-1.epic-invoicing-phase-2.cd.tamanu.app"
       Facility- 2  : "https://facility-2.epic-invoicing-phase-2.cd.tamanu.app"
       PatientPortal: "https://portal.epic-invoicing-phase-2.cd.tamanu.app"
   }

Resources:
   ~ 14 updated
   +-4 replaced
   18 changes. 49 unchanged

Duration: 59s

   

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jan 22, 2026

@chris-bes chris-bes force-pushed the epic-invoicing-phase-2 branch from 94c475f to d283f65 Compare January 27, 2026 02:52
chris-bes and others added 3 commits January 27, 2026 14:15
…patient (#9037)

* record patient insurance plans

* removed unused

* dbt

* clean up

* clean up test

* clean up test

* revert format

* dbt

* clean up

* clean up

* add relationship

* add patient merge

* fixed test

* fixed test
Comment thread packages/web/app/validations/patientDetailValidations.jsx Fixed
* invoice printout

* addressed reviews
@tcaiger tcaiger changed the base branch from main to epic-invoicing February 3, 2026 01:17
…invoice (#9052)

* record patient insurance plans

* removed unused

* dbt

* clean up

* clean up test

* clean up test

* revert format

* dbt

* clean up

* clean up

* add relationship

* add patient merge

* auto populate insurance plans

* clean up

* add more check
Base automatically changed from epic-invoicing to main February 5, 2026 04:06
Comment thread packages/web/app/validations/patientDetailValidations.jsx Fixed
chris-bes and others added 4 commits February 16, 2026 11:30
* invoice refunds

* clean up

* restyle disabled autocomplete

* address review

* remove color
* cherry pick

* draft changes

* refactor medication administration record

* refactor pharmacy order

* Update MedicationAdministrationRecord.ts

* Update PharmacyOrderPrescription.ts

* extract hooks

* refactor recalculateAndApplyInvoiceQuantity

* logic

* fix test to add

* add bulk destroy

* add bulk update

* INVOICEABLE_MEDICATION_ENCOUNTER_TYPES

* setItemQuantityForInvoice

* fix tests

* move INVOICEABLE_MEDICATION_ENCOUNTER_TYPES

* Update Prescription.ts

* Update EncounterInvoice.test.js

* Update Prescription.ts
…rom patient details if it is being used for an invoice (#9182)

* validate

* handle error

* clean up

* add tests

* fix patient invoice insurance plan

* fix failing test in epic

* fix tests
Comment thread packages/web/app/validations/patientDetailValidations.jsx Fixed
Comment thread packages/facility-server/app/routes/apiv1/patient/patient.js Fixed
});
},
),
'Insurance plan',
chris-bes and others added 5 commits February 25, 2026 12:13
…les (#9166)

* cherry pick

* draft changes

* refactor medication administration record

* refactor pharmacy order

* Update MedicationAdministrationRecord.ts

* Update PharmacyOrderPrescription.ts

* extract hooks

* refactor recalculateAndApplyInvoiceQuantity

* logic

* fix test to add

* add bulk destroy

* add bulk update

* INVOICEABLE_MEDICATION_ENCOUNTER_TYPES

* setItemQuantityForInvoice

* fix tests

* move INVOICEABLE_MEDICATION_ENCOUNTER_TYPES

* Update Prescription.ts

* Update EncounterInvoice.test.js

* Update Prescription.ts

* add approved column

* clean up

* fix patient invoice insurance plan

* remove unused

* fixed tests

* clean up

* lint

* clean up

* tweak tests

* add settings

* small fixes

* cast

---------

Co-authored-by: Tom Caiger <caigertom@gmail.com>
* add edit modal

* chore: no-issue: improve CLAUDE.md with dev commands and architecture

Adds development commands (build, test, lint, migrations) and a
high-level architecture overview for Claude Code's /init format.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Create settings.local.json

* feat(invoicing): SAV-1129: update edit invoice modal UI to match Figma

- Rename modal title to "Edit invoice" and add description text
- Add grey background to modal body with white table card
- Rename column headers: Qty→Quantity, Price→Cost
- Add Net cost column using getInvoiceItemNetCost utility
- Restyle modal footer with grey background and top border
- Update save button text to "Save changes"
- Hide "Add item" button in edit modal context

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Update settings.local.json

* feat(invoicing): SAV-1129: open add items modal from invoice screen

- Add AddInvoiceItemsModal with same grey layout as EditInvoiceItemsModal
- Add ADD_ITEMS modal type to INVOICE_MODAL_TYPES
- Wire Add item button on invoice page to open modal instead of inline edit
- Add isModal, onAddItem, startWithBlankRow props to InvoiceForm
- Modal starts with one blank row and shows + Add item inside white card

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(invoicing): SAV-1129: hide existing items from add items modal

In the add items modal, only show new blank rows rather than all
existing invoice items. On submit, merge new items with existing ones
so existing items are not wiped out.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(invoicing): SAV-1129: fix modal white strip and cancel button

- Remove mb={1} from form Box in modal/edit contexts to eliminate
  the white strip at the bottom of the modals
- Add onCancel prop to InvoiceForm for closing the modal on cancel
- Pass onCancel={handleClose} from EditInvoiceItemsModal

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* widths

* tweak(invoicing): SAV-1129: use different column widths for editable vs read-only invoice views

Wider columns in modal (editable) views to accommodate form fields, narrower in
inline read-only view. Each cell accepts a cellWidths prop defaulting to CELL_WIDTHS.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Update constants.js

* styles

* refactor

* Update InvoiceForm.jsx

* cleanup

* clean up

* Update InvoiceItemHeader.jsx

* Update NetCostCell.jsx

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…lity and central servers) (#9216)

* fix syncing self referencing FKs

* add more test

* clean up tests

* clean up

* rename

* more tests

* only defer fks for public tables that are initially immediate

* fix(sync): COOL-51: Fix syncing self referencing FKs (PART 2 for mobile) (#9234)

* sync self ref fk mobile

* clean up

* clean up

* rename
@chris-bes chris-bes merged commit 1057870 into main Mar 5, 2026
236 of 244 checks passed
@chris-bes chris-bes deleted the epic-invoicing-phase-2 branch March 5, 2026 03:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants