Developer notes
Data model
Section titled “Data model”| Table | Contents |
|---|---|
cscart_kv_ntcl_accounts |
One row per customer (user_id): status (A active, H on hold, O on hold overdue, C closed), use_group, credit_limit, terms_days, terms_basis (I invoice date, M end of month), over_limit (‘’ store default, B block, R review), notes, hold reason, dates. |
cscart_kv_ntcl_group_rules |
Usergroup terms: usergroup_id, status, limit, terms. |
cscart_kv_ntcl_invoices |
One row per net-terms leaf order (order_id): parent_order_id, user_id, company_id (vendor in Multi-Vendor), total, paid_amount, state (R review, O open, P paid, X cancelled), terms, issued_at, due_at, paid_at, po_number, the original payment_id, reminder counters, token_hash (sha256) and token_enc (encrypted copy) of the payment link. |
cscart_kv_ntcl_payments |
Payments: order, amount, method (online, manual, status), reference, note, date, staff member. |
cscart_kv_ntcl_applications |
Applications (P pending, A approved, D declined) with the form data and the decision. |
cscart_kv_ntcl_events |
History of accounts and invoices. |
cscart_kv_ntcl_throttle |
Rate limits of the payment page and the application form. |
Money is stored with 2 decimals in the primary currency; sums are made in whole cents. Balance = total − paid. Open balance of a customer = sum of the balances of invoices in review or open. Available credit = limit − open balance.
Order flow
Section titled “Order flow”get_payments_post(storefront only): net-terms methods (templateaddons/kv_net_terms_credit_limit/views/orders/components/payments/net_terms.tpl) are removed for guests and for customers without an active account with a limit, and on the core repay form.pre_place_order(top-level order, only when an order is really placed; core also callsfn_allow_place_order()while rendering the checkout): licence, account status, PO number, and the order total against the available credit, under a per-customerGET_LOCKthat is released inplace_order_post. Over the limit: refuse, or set$cart['kv_ntcl']['review'].place_order: for each leaf order paid with a net-terms method the add-on writes the invoice and sets$order_statusto Awaiting payment (net terms) or Credit review (the call_requests pattern). The parent order of a Multi-Vendor checkout keeps its core status; its sub-orders are placed with copies of the cart and get their own invoices. Order editing recalculates the invoice total and never changes the status.change_order_status_post: a paid status records the rest of the balance; Awaiting payment approves a review; Canceled/Declined/Failed cancels the invoice; leaving those statuses reopens it. The invoice e-mail is sent once, when the invoice is open and has the awaiting status.
The statuses are created at installation with fn_update_status() and marked with the status parameter kv_ntcl_status (awaiting / review), so a reinstall reuses them: inventory D (stock reserved), payment_received N, calculate_for_payouts N, repay N, allow_return N.
Payment flow (same order)
Section titled “Payment flow (same order)”The payment page (kv_net_terms_credit_limit.pay?t=<token>) charges the open balance of the same order like core repay: it stores the payment data in ?:order_data (type P, encrypted, the PO number is kept), switches the order’s payment_id to the chosen method and calls fn_start_payment().
get_order_info: only when called byfn_start_payment()or from a payment script (*/payments/*.php), the ordertotalof a partly paid invoice is the open balance. Every other reader keeps the order total.finish_payment: a paid status records an online payment for the balance (reference = transaction id); any other status maps the order back to Awaiting payment (net terms) and restores the net-terms payment method, so a failed card never cancels or restocks the order.change_order_status_child_orderapplies the same mapping to sub-orders paid through a parent.order_placement_routines: after a gateway returns, the customer comes back to the payment page.
Tokens: 24 random bytes (base64url) + an HMAC-SHA256 tag keyed with the store’s crypt key. A wrong tag is rejected before any database lookup. The page is rate-limited per IP (bad tokens) and per invoice (payment attempts), sends Cache-Control: no-store, X-Robots-Tag: noindex and Referrer-Policy: no-referrer, and never stores card data.
| Hook | Use |
|---|---|
get_payments_post |
Hide net terms for customers who may not use it |
pre_place_order |
Credit check, PO number, lock |
place_order, place_order_post |
Invoice and status; release the lock |
get_order_info |
Open balance for gateways |
finish_payment, change_order_status_child_order, change_order_status_post |
Payment and status mapping |
order_placement_routines |
Back to the payment page |
delete_order, post_delete_user |
Clean-up |
template_snippet_render_post |
Terms, due date, PO number on the bill_to snippet of order documents |
before_dispatch |
Admin fallback of the schedule |
All hook lines are identical in CS-Cart 4.17.2 and 4.21.2.
Documents
Section titled “Documents”Order documents (Design → Documents) get the payment terms automatically. For a custom layout use the document variable:
{% if kv_net_terms.is_invoice %} {{ kv_net_terms.terms }} · {{ __("kv_net_terms_credit_limit.due_date") }}: {{ kv_net_terms.due_date }} {% if kv_net_terms.po_number %}PO {{ kv_net_terms.po_number }}{% endif %}{% endif %}Fields: is_invoice, terms, due_date, po_number, balance, paid, status, instructions.
E-mail templates
Section titled “E-mail templates”Design → E-mail templates: kv_net_terms_credit_limit_invoice, _reminder (before and after the due date, is_overdue), _receipt, _account (what: approved, hold, released, closed), _application (received, declined) and _admin (store notices). All are valid in Twig 2 and Twig 3.
Schedule
Section titled “Schedule”php admin.php --dispatch=kv_net_terms_credit_limit.run (console), index.php?dispatch=kv_net_terms_credit_limit.cron&key=<key> (URL) or the admin fallback (every 30 minutes, after the page was sent). A lock prevents parallel runs; run marks live in storage_data, or in files under var/kv_storage/ while the full page cache is on.
Caching
Section titled “Caching”Nothing is printed on cacheable pages (home, categories, products, pages). The checkout, the account pages, the payment page and the cron URL are not cacheable dispatches and send no-store. The “Invoices & credit” link sits in the My account block, which the full page cache renders per visitor (ESI). Storefront GETs write nothing to storage_data.
PHP API
Section titled “PHP API”use Tygh\Addons\KvNetTermsCreditLimit\Accounts;use Tygh\Addons\KvNetTermsCreditLimit\Invoices;
$summary = Accounts::summary($user_id); // limit, open, available, overdue, terms_text, status ... or nullAccounts::save($user_id, ['credit_limit' => 5000, 'terms_days' => 30, 'terms_basis' => 'I', 'status' => 'A']);Invoices::recordPayment($order_id, 150.00, 'manual', 'Bank ref 123', ['note' => 'Wire']);list($errors, $allocations) = Invoices::allocate($user_id, 900.00, 'Bank ref 124');File map
Section titled “File map”app/addons/kv_net_terms_credit_limit/ addon.xml, init.php, func.php controllers/backend/kv_net_terms_credit_limit.php accounts, invoices, applications, aging, rules, statement, actions, console cron controllers/backend/kv_net_terms_credit_limit_license.php "Check now" / license cron controllers/backend/orders.post.php invoice panel data controllers/frontend/kv_net_terms_credit_limit.php invoices & credit, application, statement, payment page, cron URL controllers/frontend/checkout.post.php credit summary for the payment form controllers/frontend/orders.post.php customer order page data schemas/menu/menu.post.php, schemas/permissions/admin.post.php, vendor_multivendor.post.php schemas/documents/order.post.php, schemas/settings/variants.functions.post.php, actions.functions.post.php Tygh/Addons/KvNetTermsCreditLimit/ Config.php Install.php Money.php Accounts.php Invoices.php Checkout.php Gateway.php PayPage.php Notifier.php Scheduler.php Applications.php Reports.php Documents.php Documents/Order/NetTermsVariable.php Token.php Throttle.php StorageData.php License/Client.php License/Ed25519.php Upgrade/Synchronizer.phpdesign/backend/templates/addons/kv_net_terms_credit_limit/ views/kv_net_terms_credit_limit/{manage,account,invoices,applications,application,aging,rules,statement_print}.tpl, components/* views/orders/components/payments/net_terms.tpl, hooks/orders/details_sidebar.post.tpl, settings/cron_info.tpl, license/*design/backend/css/addons/kv_net_terms_credit_limit/styles.less, license.lessvar/themes_repository/responsive/templates/addons/kv_net_terms_credit_limit/ views/kv_net_terms_credit_limit/{invoices,apply,pay,statement_print}.tpl views/orders/components/payments/net_terms.tpl, hooks/profiles/my_account_menu.post.tpl, hooks/orders/repay.pre.tplvar/themes_repository/responsive/css/addons/kv_net_terms_credit_limit/styles.lessjs/addons/kv_net_terms_credit_limit/func.jsvar/langs/en/addons/kv_net_terms_credit_limit.poLicense
Section titled “License”The add-on ships the generated License\Client. Gated (switched off without a valid license): the visibility of the Net terms payment method, new net-terms orders and new applications. Not gated: payment links and online payments of existing invoices, the gateway amount, the payment and status mapping, recorded payments, reminders, overdue detection, the automatic hold, statements, the aging report and the admin pages, so a started customer transaction always completes.