Skip to content

Credit-card payment approval

Purchases charged to a SAIF credit card cannot be paid on the specialist's own authority: entering a credit-card transaction date forces the expense into supervisor approval regardless of amount. This operation is the supervisor's side of that gate. It reads the credit-card purchases charged by one EAIP user, shows the supervisor a review list stamped with their own formatted name, and applies a single approve-or-return decision to every row the supervisor selected — advancing approved expenses to PAY and returning the rest to NEW.

Field Value
Operation ID OP-EAIP-04
Trigger Supervisor invokes clsCreditCardPayment.GetCreditPayments(dpi, eaipUser), sets SupervisorApproved on the rows to act on, and calls clsCreditCardPayments.SaveChanges(approved)
Inputs IDataPortalInfo (acting supervisor), the EAIP user whose credit-card charges are under review, the per-row supervisor-approved selections, and the single approved/returned decision flag
Outputs A read-only review collection carrying claim number, worker name, expense type, description, paid amount, credit-card paid date, vendor invoice number, and update number; expense status updates to PAY or NEW; the total of the selected amounts; a DB contention error when a status update affects no rows
Primary components clsCreditCardPayment (Fill, Load, UpdateExpenseStatus), clsCreditCardPayments (SaveChanges, TotalIncluded, Approver), clsPurchase (CreditCardPaidDate setter, NeedsApproval override)
Entry point Business\SAIF.Business.Claim.EAIP\Period\clsCreditCardPayments.vb

Steps

  1. Stamp the charge on the purchase. Upstream of this operation, the specialist sets CreditCardPaidDate on a purchase. That setter also writes the acting user's identifier, upper-cased, into CreditCardUser — or clears it when the date is removed. Those two columns are what the review query filters on, so a purchase charged by one user never appears in another user's review list (BR-PROC-003).
  2. Force the expense into approval. clsPurchase.NeedsApproval() returns true immediately — before any authority, adjustment, or limit checks — when a credit-card transaction date is present and the purchase sits in Pay status, adding the warning "Supervisor approval is required when credit card trans date is entered." The expense save path then demotes the purchase to PendingSupervisorApproval (BR-PROC-006). Full detail of that gate is on Expense lifecycle and payment approval.
  3. Open the review list. GetCreditPayments(inDPI, inEaipUser) creates the collection and loads it from pk82500_EAIP.credit_payment_select, binding only the EAIP user whose charges are being reviewed (Details). The package restricts the result to purchases with a non-null credit-card paid date whose credit-card user matches the parameter (BR-PROC-003).
  4. Resolve the approver's display name. Before loading the rows, the factory reads the acting supervisor's employee record by mail identifier, sets the name format to standard-first, and stores the formatted name on the collection as Approver. That value exists purely so the review screen and any printed approval record show who reviewed the charges rather than a mail identifier.*
  5. Materialize the rows. Each row is filled into a clsCreditCardPayment carrying the credit-card paid date, claim number, worker name, expense type description, paid amount, expense identifier, item description, vendor invoice number, and — critically — the current update number, which is the row version the later status update will compare against. Each item is then marked old. All properties except the supervisor-approved flag are read-only: this object cannot edit an expense, only decide it.
  6. Select rows and total them. The supervisor sets SupervisorApproved on the rows to act on. TotalIncluded sums the paid amounts of exactly those rows, giving the supervisor the value of the batch they are about to release.
  7. Apply the decision. SaveChanges(inApproved) resolves one status code for the whole batch — PAY when approved, NEW when not — and then loops the collection, acting only on rows the supervisor selected. A returned (not approved) charge therefore goes back to NEW for the specialist to rework rather than being deleted or denied.
  8. Update each expense status. For each selected row, UpdateExpenseStatus(newStatusCode) builds a scalar stored-procedure request against pk82500_eaip.update_expense_status and binds the expense identifier, the new status code, the acting supervisor as update user, the current timestamp, the incremented update number, the original update number as LastUpdateNum, and a RowsAffected return parameter (SQL-027, Details). The package updates only when the stored update number still matches, and returns the affected row count (BR-PROC-001).
  9. Stop on the first contention failure. UpdateExpenseStatus returns true only when exactly one row was affected. On anything else, SaveChanges adds an UpdateError carrying the DB contention message to the collection and returns false immediately — the remaining selected rows are not attempted, so a partially applied batch is possible.
  10. Refresh. Because the collection holds the update numbers captured at load time and does not re-read them after a successful update, the caller must reload through GetCreditPayments before acting on the same rows again; a second decision applied to the stale collection compares an out-of-date update number and fails the concurrency check.*

Process flow

The following diagram visualizes this operation's control flow.

flowchart TD
    Start([Specialist enters credit card<br>transaction date on a purchase]) --> Stamp[CreditCardUser set to<br>acting user, upper-cased]
    Stamp --> Force[NeedsApproval returns true;<br>purchase demoted to<br>PendingSupervisorApproval]
    Force --> Open([Supervisor opens review list])
    Open --> Emp[Resolve supervisor employee record;<br>store formatted name as Approver]
    Emp --> Load[credit_payment_select filtered by<br>credit card user and non-null paid date]
    Load --> Rows[Rows filled read-only with<br>amount, description, update number]
    Rows --> Select[Supervisor sets SupervisorApproved<br>on chosen rows; TotalIncluded sums them]
    Select --> Decide{Approved?}
    Decide -->|Yes| Code[New status code = PAY]
    Decide -->|No| Code2[New status code = NEW]
    Code --> Loop[For each selected row:<br>update_expense_status with<br>LastUpdateNum check]
    Code2 --> Loop
    Loop --> Rows1{RowsAffected = 1?}
    Rows1 -->|No| Stop([UpdateError with DB contention message;<br>remaining rows not attempted])
    Rows1 -->|Yes| Next{More selected rows?}
    Next -->|Yes| Loop
    Next -->|No| Done([Batch applied; caller must reload<br>before acting again])

Failure and edge-case behavior

  • The batch is not transactional in this code. SaveChanges returns false at the first contention failure, leaving every earlier row already updated and every later row untouched.
  • Update numbers are captured when the list is loaded and never refreshed. Any change to an expense between load and decision — including one made by the specialist in another session — invalidates the pending decision for that row.
  • The item class registers no business rules at all; its rule-registration method is empty. Nothing in this operation re-checks authority, amount limits, or expense type, so the decision rests entirely on the package's filter and the supervisor's judgement.
  • Both criteria classes throw an invalid-statement exception from every statement property, so no create, retrieve, update, or delete can be issued through the ordinary data-portal path; the only database writes are the explicit status-update calls, and the only read is the package select.
  • Returning a charge sets the expense back to NEW, which clears it from the supervisor's queue but leaves the credit-card transaction date and credit-card user in place; unless the specialist clears them, the expense re-enters the same queue on the next attempt to pay.*
  • A row that the supervisor did not select is skipped entirely, so an unattended row stays in PendingSupervisorApproval indefinitely.

Note: Statements marked with * were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts.

Sources

  • Business\SAIF.Business.Claim.EAIP\Period\clsCreditCardPayments.vb
  • Business\SAIF.Business.Claim.EAIP\Period\clsPurchase.vb
  • Business\SAIF.Business.Claim.EAIP\Period\clsExpense.vb