fdf62dafef
Move-code split, public entry points unchanged: - services/invoiceService.js (3,623 -> 99) + services/invoice/* (10 modules) - services/contractService.js (2,363 -> 83) + services/contract/* (6 modules) - routes/adminEvents.js -> routes/adminEvents/* (crud, slideshow, resets, archive/bulk, logo); route registration order verified identical Lazy cross-service requires preserved to keep the module graph acyclic.
84 lines
3.2 KiB
JavaScript
84 lines
3.2 KiB
JavaScript
/**
|
|
* contractService — orchestrates the lifecycle of `contracts`, their
|
|
* `contract_block_inclusions` (which blocks from the library make it
|
|
* onto a given contract), and the public `contract_action_tokens` used
|
|
* by the customer's signing link.
|
|
*
|
|
* Contracts are an INDEPENDENT document type alongside quotes and
|
|
* invoices. Composition model:
|
|
* - Admin picks blocks from the `contract_blocks` library and toggles
|
|
* them on/off per section (basics → scope → privacy → commercial →
|
|
* nda → closing). Order within a section is admin-controlled.
|
|
* - On send, every included block's body is FROZEN into
|
|
* `body_text_snapshot` on the inclusion row, so future edits to
|
|
* the source block don't mutate already-sent contracts.
|
|
*
|
|
* Signing:
|
|
* 1. Customer opens /contract/:token and either:
|
|
* a) Types name, optionally draws a signature on canvas, ticks
|
|
* "I have read and agree", submits → recordCustomerSignature
|
|
* stamps the signature into a re-rendered PDF and the system
|
|
* emails the admin.
|
|
* b) Uploads a wet-signed PDF → attachSignedPdfUpload sets the
|
|
* signed_pdf_path as the authoritative copy.
|
|
* 2. Admin counter-signs (in-browser or by re-uploading the
|
|
* double-signed PDF) → status flips to `fully_signed`.
|
|
*
|
|
* Bodies support {{placeholders}} resolved at PDF/preview render time
|
|
* using the same Handlebars-lite regex that emailProcessor.safeTemplateReplace
|
|
* uses. We rebuild it inline here (not exported from emailProcessor) to
|
|
* keep the dependency tree shallow and so contracts can render
|
|
* client-side previews in the future without pulling the email
|
|
* processor.
|
|
*/
|
|
//
|
|
// Decomposed into ./contract/* modules (move-code refactor). This file is the
|
|
// stable public entry point: same require path, same exported names.
|
|
|
|
const helpers = require('./contract/helpers');
|
|
const renderContext = require('./contract/renderContext');
|
|
const crud = require('./contract/crud');
|
|
const sending = require('./contract/sending');
|
|
const signatures = require('./contract/signatures');
|
|
const conversions = require('./contract/conversions');
|
|
|
|
const { SECTIONS_ORDER, nextContractNumber } = helpers;
|
|
const { renderTemplatedBody, buildPlaceholderContext, buildRenderContext } = renderContext;
|
|
const {
|
|
listContracts, getContractById, createContract, updateContract, cancelContract,
|
|
} = crud;
|
|
const { renderContractPdfBuffer, sendContract } = sending;
|
|
const {
|
|
recordCustomerSignature, recordAdminCountersignature, attachSignedPdfUpload,
|
|
rerenderAndResend, restampSignatures, getAuditTrail, verifyIntegrity,
|
|
} = signatures;
|
|
const { createFromQuote, convertToEvent, convertToInvoiceOnly } = conversions;
|
|
|
|
module.exports = {
|
|
listContracts,
|
|
getContractById,
|
|
createContract,
|
|
updateContract,
|
|
sendContract,
|
|
renderContractPdfBuffer,
|
|
recordCustomerSignature,
|
|
recordAdminCountersignature,
|
|
attachSignedPdfUpload,
|
|
cancelContract,
|
|
createFromQuote,
|
|
convertToEvent,
|
|
convertToInvoiceOnly,
|
|
rerenderAndResend,
|
|
restampSignatures,
|
|
getAuditTrail,
|
|
verifyIntegrity,
|
|
// Exported for tests + the public-route preview endpoint.
|
|
_internal: {
|
|
nextContractNumber,
|
|
renderTemplatedBody,
|
|
buildPlaceholderContext,
|
|
buildRenderContext,
|
|
SECTIONS_ORDER,
|
|
},
|
|
};
|