40 lines
5.0 KiB
PHP
40 lines
5.0 KiB
PHP
<?php
|
|
namespace Tempo\Finance\GeneralLedger;
|
|
use Illuminate\Database\ConnectionInterface;
|
|
/** New owned books only. Legacy supplier constraint remains responsible for its original domain. */
|
|
final class IndustrialCorrectionSchema
|
|
{
|
|
public static function install(ConnectionInterface $db):void
|
|
{
|
|
LedgerSchema::assertSynthetic($db);
|
|
if(!str_starts_with($db->getDatabaseName(),'payable_sgf_')||!$db->getSchemaBuilder()->hasTable('gl_industrial_sources')||$db->getSchemaBuilder()->hasTable('gl_industrial_correction_capability')||$db->table('gl_proposals')->exists()||$db->table('gl_journals')->exists())throw new \LogicException('New empty SGF cost correction book required');
|
|
$db->transaction(function()use($db){
|
|
$db->statement('CREATE TABLE gl_industrial_correction_capability(id int PRIMARY KEY CHECK(id=1),contract text NOT NULL)');$db->table('gl_industrial_correction_capability')->insert(['id'=>1,'contract'=>'COMMON-LEDGER-INDUSTRIAL-CORRECTION-SIM-v1']);$db->unprepared('CREATE TRIGGER gl_immutable BEFORE UPDATE OR DELETE ON gl_industrial_correction_capability FOR EACH ROW EXECUTE FUNCTION gl_append_only()');
|
|
$db->unprepared(<<<'SQL'
|
|
CREATE FUNCTION gl_industrial_pair_assert(cid bigint) RETURNS void LANGUAGE plpgsql AS $$ BEGIN
|
|
IF NOT EXISTS(SELECT 1 FROM gl_correction_results r JOIN gl_corrections c ON c.id=r.correction_id JOIN gl_journals o ON o.id=r.original_journal_id JOIN gl_journals a ON a.id=r.reverse_journal_id JOIN gl_journals b ON b.id=r.replacement_journal_id
|
|
WHERE c.id=cid AND c.original_journal_id=r.original_journal_id AND c.prepared_by=r.actor_id AND a.proposal_id=c.reverse_proposal_id AND b.proposal_id=c.replacement_proposal_id
|
|
AND (c.tenant_id,c.company_id,c.unit_id)=(r.tenant_id,r.company_id,r.unit_id) AND (o.tenant_id,o.company_id,o.unit_id)=(r.tenant_id,r.company_id,r.unit_id) AND (a.tenant_id,a.company_id,a.unit_id)=(r.tenant_id,r.company_id,r.unit_id) AND (b.tenant_id,b.company_id,b.unit_id)=(r.tenant_id,r.company_id,r.unit_id)
|
|
AND o.snapshot->'source'->>'effect_type'='industry.cost.validated' AND a.snapshot->'source'->>'effect_type'='industry.cost.reversal' AND b.snapshot->'source'->>'effect_type'='industry.cost.replacement'
|
|
AND (a.snapshot->'source'->>'source_id')::bigint=o.id AND (b.snapshot->'source'->>'source_id')::bigint=o.id AND (a.snapshot->'source'->>'original_journal_id')::bigint=o.id AND (b.snapshot->'source'->>'original_journal_id')::bigint=o.id
|
|
AND a.snapshot->'source'->>'industrial_lot_id'=o.snapshot->'source'->>'industrial_lot_id' AND b.snapshot->'source'->>'industrial_lot_id'=o.snapshot->'source'->>'industrial_lot_id' AND a.snapshot->'source'->>'origin_key'=o.snapshot->'source'->>'origin_key' AND b.snapshot->'source'->>'origin_key'=o.snapshot->'source'->>'origin_key'
|
|
AND a.snapshot->'source'->>'replacement_source_revision'=b.snapshot->'source'->>'replacement_source_revision' AND a.debit_minor=o.debit_minor AND b.debit_minor=(b.snapshot->'source'->>'principal_minor')::bigint
|
|
AND a.snapshot->'period'->>'period_key'=o.snapshot->'period'->>'period_key' AND b.snapshot->'period'->>'period_key'=o.snapshot->'period'->>'period_key' AND a.journal_on>=o.journal_on AND b.journal_on=a.journal_on
|
|
AND NOT EXISTS(SELECT 1 FROM gl_lines l WHERE l.journal_id=o.id AND NOT EXISTS(SELECT 1 FROM gl_lines rev WHERE rev.journal_id=a.id AND rev.account_id=l.account_id AND rev.debit_minor=l.credit_minor AND rev.credit_minor=l.debit_minor))
|
|
AND b.snapshot->'lines'->0->>'account_id'=o.snapshot->'lines'->0->>'account_id' AND b.snapshot->'lines'->1->>'account_id'=o.snapshot->'lines'->1->>'account_id') THEN RAISE EXCEPTION 'GL_INDUSTRIAL_CORRECTION_PAIR_REQUIRED' USING ERRCODE='23514'; END IF;
|
|
END $$;
|
|
CREATE FUNCTION gl_industrial_pair_trigger() RETURNS trigger LANGUAGE plpgsql AS $$ DECLARE cid bigint; BEGIN
|
|
IF NEW.snapshot->'source'->>'effect_type' IN('industry.cost.reversal','industry.cost.replacement') THEN
|
|
SELECT correction_id INTO cid FROM gl_correction_results WHERE reverse_journal_id=NEW.id OR replacement_journal_id=NEW.id;
|
|
IF cid IS NULL THEN RAISE EXCEPTION 'GL_INDUSTRIAL_CORRECTION_PAIR_REQUIRED' USING ERRCODE='23514'; END IF; PERFORM gl_industrial_pair_assert(cid); END IF; RETURN NEW; END $$;
|
|
CREATE CONSTRAINT TRIGGER gl_industrial_pair AFTER INSERT ON gl_journals DEFERRABLE INITIALLY DEFERRED FOR EACH ROW EXECUTE FUNCTION gl_industrial_pair_trigger();
|
|
SQL);
|
|
$definition=$db->selectOne("SELECT pg_get_functiondef('gl_cycle_pair_integrity()'::regprocedure) d")->d;
|
|
$needle=" IF TG_TABLE_NAME='gl_journals' THEN";
|
|
if(!str_contains($definition,$needle))throw new \LogicException('Unexpected legacy pair contract');
|
|
$delegation=" IF TG_TABLE_NAME='gl_correction_results' THEN IF EXISTS(SELECT 1 FROM gl_journals WHERE id=NEW.reverse_journal_id AND snapshot->'source'->>'effect_type'='industry.cost.reversal') THEN PERFORM gl_industrial_pair_assert(NEW.correction_id); RETURN NEW; END IF; END IF;\n";
|
|
$db->unprepared(str_replace($needle,$delegation.$needle,$definition));
|
|
});
|
|
}
|
|
}
|