NovinkaZverejnili sme 50+ Laravel balíkov ako open source
Custom AI apps, agents and automation — Roundly ConsultingRoundly
Všetky balíky
Approvals for Laravel

Viacstupňové schvaľovanie

Žiadosť môže prebiehať ako usporiadaný rad stupňov. Stupeň N sa otvorí, až keď stupeň N−1 prejde; predvolene zamietnutie v ktoromkoľvek stupni zamietne celú žiadosť:

use RoundlyConsulting\Approvals\DataTransferObjects\StageDefinition;
use RoundlyConsulting\Approvals\Enums\ApprovalRule;
use RoundlyConsulting\Approvals\Facades\Approvals;

Approvals::request($release)->stages([
    new StageDefinition([$eng1, $eng2], ApprovalRule::Unanimous, name: 'engineering'),
    new StageDefinition([$product],     ApprovalRule::Any,       name: 'product'),
])->expiringAt($deadline)->open();

Approvals::currentStage($release);   // ?ApprovalRequestStage — the open stage
Approvals::progress($release);       // ?ApprovalProgress — counts, current/total stages, percentage()

Ak jednému builderu odovzdáte from() aj stages(), vznikne InvalidApprovalRequestException. Na modeli s RequiresApproval má to isté schvaľovanie skratku:

// RequiresApproval shorthand — the same pipeline through the same manager
$release->requestStagedApproval($stages, rejectOnStageRejection: true, expiresAt: $deadline);

$release->currentStage();       // ?ApprovalRequestStage
$release->approvalProgress();   // ?ApprovalProgress

Priebeh krok za krokom

Schvaľovatelia rozhodujú o subjekte ako zvyčajne. Každé rozhodnutie sa pripojí k práve otvorenému stupňu a schvaľovanie sa posúva samo:

Approvals::for($release)->as($eng1)->approve();
Approvals::for($release)->as($eng2)->approve();   // engineering clears -> ApprovalStageCleared, product opens -> ApprovalStageOpened

Approvals::currentStage($release)->name;       // 'product'
Approvals::progress($release)->percentage();   // 50 — one of two stages cleared

Approvals::for($release)->as($product)->approve();   // the last stage clears -> the request is approved
Approvals::status($release);                         // ApprovalStatus::Approved

O otvorenom stupni rozhodujú len jeho schvaľovatelia — schvaľovateľ neskoršieho stupňa či ktokoľvek zvonka dostane UnauthorizedApprovalException, kým sa daný stupeň neotvorí. Aj stiahnutie zasiahne len otvorený stupeň: rozhodnutia už uzavretého stupňa zostanú, ako sú. Keď je žiadosť uzavretá alebo jej uplynula platnosť, currentStage() vráti null.

StageDefinition

new StageDefinition(
    array $approvers,                              // list<Model> — the stage's named approvers; [] lets anyone decide
    ApprovalRule $rule = ApprovalRule::Unanimous,
    ?int $quorum = null,
    ?string $name = null,
    ?int $requiredApprovers = null,                // approvals the stage needs; one per named approver by default
);

// A stage that names nobody: any approver may decide it.
new StageDefinition([], ApprovalRule::Any, requiredApprovers: 1);

Každý stupeň má vlastné pravidlo, kvórum, názov a menovaných schvaľovateľov. Potrebuje jedno schválenie na menovaného schvaľovateľa, ak requiredApprovers neurčí inak, a nemusí vymenovať nikoho — vtedy oň môže rozhodnúť ktokoľvek, ak má pravidlo, ktoré sa dá splniť aj bez mien (Any, kvórum alebo requiredApprovers); inak otvorenie vyhodí InvalidApprovalRequestException.

Pokračovanie po zamietnutom stupni

S continueOnRejection() — alebo s rejectOnStageRejection: false v traite — schvaľovanie po zamietnutom stupni pokračuje. Keď sa uzavrú všetky stupne, žiadosť je schválená, ak aspoň jeden stupeň prešiel schválením, inak je zamietnutá:

Approvals::request($release)->stages([
    new StageDefinition([$legal], ApprovalRule::Any, name: 'legal'),
    new StageDefinition([$cfo, $ceo], ApprovalRule::Quorum, quorum: 1, name: 'executive'),
])->continueOnRejection()->open();

Stupne a udalosti

  • Prvý stupeň sa otvorí okamžite a spustí ApprovalStageOpened.
  • Keď stupeň prejde schválením, spustí sa ApprovalStageCleared a otvorí sa ďalší stupeň s ApprovalStageOpened — vrátane stupňa po zamietnutom, za ktorý schvaľovanie pokračuje.
  • Keď sa stupeň uzavrie, vyžiadania, ktoré v ňom ešte čakajú, sa zrušia — každé spustí ApprovalCancelled a ApprovalStatusChanged.
  • Keď sa uzavrie posledný stupeň — alebo zamietnutie stupňa ukončí schvaľovanie — spustia sa pre žiadosť ApprovalRequestResolved a ApprovalStatusChanged.
  • Keď vaša aplikácia odovzdá otvorený stupeň iným schvaľovateľom, spustí sa ApprovalApproversReplaced a potom preň znova ApprovalStageOpened — pozri nižšie.

Odovzdanie stupňa iným schvaľovateľom

Keď otvorený stupeň musí prevziať niekto iný — „odovzdaj to môjmu manažérovi“ —, nahraďte jeho čakajúcich schvaľovateľov priamo na mieste namiesto toho, aby ste kolo uzavreli a otvorili nové. $stage je názov stupňa zo StageDefinition alebo zo šablóny workflow; nahradiť sa dá len stupeň otvorený na rozhodovanie. Bez within() sa použije otvorené kolo subjektu:

use RoundlyConsulting\Approvals\DataTransferObjects\StageDefinition;
use RoundlyConsulting\Approvals\Facades\Approvals;

$round = Approvals::request($release)->stages([
    new StageDefinition([$eng1, $eng2, $eng3], name: 'engineering'),   // Unanimous by default
    new StageDefinition([$product], name: 'product'),
])->open();

Approvals::for($release)->as($eng1)->approve();

// eng2 and eng3 are out this week: the engineering stage goes to $manager.
$round = Approvals::for($release)->within($round)->replaceApprovers('engineering', [$manager]);

// The stage now names eng1 (decided, still counting) and $manager, and needs both.
Approvals::for($release)->as($eng2)->approve();      // UnauthorizedApprovalException — no longer named
Approvals::for($release)->as($manager)->approve();   // engineering clears, product opens
  • Nový zoznam tvoria schvaľovatelia, ktorí o stupni už rozhodli — schválili alebo zamietli, aj cez zástupcu —, a za nimi tí, ktorých odovzdáte; každý sa ohodnotí váhou voči subjektu rovnako ako pri otvorení kola. Schvaľovatelia, ktorí ešte nerozhodli, vypadnú.
  • Stupeň, ktorý potreboval všetkých menovaných schvaľovateľov, ich potrebuje všetkých aj naďalej, takže jeho počet potrebných schválení sa riadi novým zoznamom; explicitný počet zostane, aký bol. Pravidlo aj kvórum zostanú a celkový počet potrebných schválení kola sa prispôsobí jeho stupňom.
  • Nevybavené vyžiadania vyradených schvaľovateľov sa stiahnu — pre každé ApprovalCancelled a ApprovalStatusChanged (pending → cancelled). Schvaľovateľ, ktorého znova uvediete, si vyžiadanie ponechá.
  • Spustí sa ApprovalApproversReplaced so stupňom a pridanými aj odobranými schvaľovateľmi, potom pre stupeň znova ApprovalStageOpened s novými schvaľovateľmi, aby ich listener mohol upozorniť.
  • Ponechá už urobené rozhodnutia, absolútnu expiráciu kola, čas otvorenia stupňa aj workflow kola — a kolo nikdy nevyhodnotí: nespustí sa ApprovalRequestResolved ani ApprovalStageCleared.
  • Nie je pri tom žiadny aktér a nespúšťa sa žiadna autorizačná Gate: kto smie stupeň preradiť, overte pred volaním. Noví schvaľovatelia pri rozhodovaní cez Gate prechádzajú ako zvyčajne.

Každé odmietnutie vyhodí výnimku ešte pred akýmkoľvek zápisom, takže sa nič nezmení, nespustí sa žiadna udalosť a Approvals::fake() nič nezaznamená:

Odmietne sa, keďVýnimka (factory)
Zoznam schvaľovateľov je prázdny — stupeň bez mien by mohol rozhodnúť ktokoľvek.InvalidApprovalRequestException (noReplacementApprovers)
Kolo je uzavreté — schválené, zamietnuté, zrušené či expirované — alebo sú uzavreté všetky kolá subjektu.ClosedApprovalRequestException (for)
Kolu uplynula platnosť; tu sa nenechá vypršať, lebo by sa tým vyhodnotilo.ClosedApprovalRequestException (overdue)
Kolo je jednostupňové.InvalidApprovalRequestException (notStaged)
Žiadny stupeň nemá taký názov.InvalidApprovalRequestException (unknownStage)
Stupeň je už uzavretý alebo sa ešte neotvoril.InvalidApprovalRequestException (stageNotOpen)
Schvaľovateľ zo zoznamu už o stupni rozhodol — jeho rozhodnutie platí.InvalidApprovalRequestException (alreadyDecided)
Schvaľovateľ nebol nikdy uložený.InvalidApprovalRequestException (unsavedApprover)
Explicitný počet potrebných schválení je vyšší než dĺžka nového zoznamu alebo prah kvóra či váhy, ktorý nový zoznam nikdy nedosiahne.InvalidApprovalRequestException (moreRequiredThanNamed, unreachableThreshold)
Už urobené rozhodnutia by stupeň podľa jeho pravidla hneď uzavreli.InvalidApprovalRequestException (replacementSettlesStage)
Kolo z within() patrí inému subjektu alebo subjekt nikdy kolo nemal.InvalidApprovalRequestException (foreignSubject, noRound)
Bolo nastavené as(), because(), weight() alebo expirácia.InvalidApprovalRequestException (settingsOnReplace)

Jednostupňové kolo — bez stupňov — odovzdáte cez replaceFlatApprovers(); pozri Ochrana rozhodnutí. Vylúčeného schvaľovateľa nemôže uviesť ani jedna výmena (excludedApprover).

Výmena zapisuje v jednej transakcii pod zámkom riadka kola — tým istým, ktorý si pred zápisom berie každé rozhodnutie. Rozhodnutie či vyžiadanie od schvaľovateľa, ktorého výmena vyradila, alebo od jeho zástupcu, ktoré bolo ešte na ceste, sa po dosiahnutí zámku odmietne s UnauthorizedApprovalException, namiesto toho, aby sa zapísalo. Zástupca nového schvaľovateľa môže rozhodnúť zaňho.

Model stupňa

$stage = Approvals::currentStage($release);   // ?ApprovalRequestStage

$stage->position;             // 1-based order in the pipeline
$stage->name;                 // 'engineering'
$stage->rule;                 // ApprovalRule
$stage->required_approvers;   // approvals the stage needs
$stage->namedApprovers();     // list<NamedApprover> — empty when it names nobody
$stage->status;               // ApprovalStatus
$stage->opened_at;            // ?CarbonImmutable
$stage->cleared_at;           // ?CarbonImmutable — set when the stage settles
$stage->isOpen();             // pending and opened
$stage->decisions;            // decisions recorded against this stage
$stage->request;              // the ApprovalRequest

Prejavte lásku k open source

Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.

Ďalšie spôsoby podpory vrátane kryptomien

Odoslaním daru súhlasíte s našimi podmienkami prijímania darov.

Chcete to zabudovať do svojho produktu?

Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.