Skip to main content

InventoryWriteService

Struct InventoryWriteService 

Source
pub struct InventoryWriteService { /* private fields */ }

Implementations§

Source§

impl InventoryWriteService

Source

pub fn new(db_pool: PgPool) -> Self

Source

pub fn with_sink(db_pool: PgPool, sink: Arc<dyn InventoryEventSink>) -> Self

Source§

impl InventoryWriteService

Source§

impl InventoryWriteService

Source

pub async fn create_purchase_receipt( &self, r: NewReceipt, ) -> Result<Uuid, InventoryError>

Source

pub async fn submit_purchase_receipt( &self, id: Uuid, sink: &dyn GlPostSink, ) -> Result<SubmitOutcome, InventoryError>

Submit the goods-in voucher. Every line mints ONE stock move through the converged engine (supplier location → the warehouse’s stock location): confirm → assign (an inbound move’s supply is unconditionally available, so the execution line covers the full line) → done, which materializes the destination quant, reblends the Bin (value += qty·rate; rate = value/qty) and mints the SLE row. The voucher keeps its identity verbatim — header status, the ONE Dr Inventory · Cr GR/IR envelope, the posting_state/repost machinery, the StockReceived event; the moves post no GL (empty directive + the door-owned-GL tripwire sink).

Not cross-move atomic (each engine verb commits its own transaction): a crash mid-way leaves the receipt draft with some line moves landed — the deterministic move names ({receipt_number}/{seq}, origin = the receipt number) make a re-submit RESUME instead of double-receiving.

Source

pub async fn submit_purchase_receipt_into( &self, id: Uuid, destination_location_id: Option<Uuid>, sink: &dyn GlPostSink, ) -> Result<SubmitOutcome, InventoryError>

Submit a receipt into a destination other than the warehouse’s stock location.

The ordinary receipt lands on the shelf, which is what a goods receipt means. A subcontract receipt does not: the supplier’s output belongs to an open manufacturing order, and landing it on the shelf makes the estate believe in it twice, once here and once when that order is received. The caller passes the location the goods are really standing in — the production counterpart — and the manufacturing receive moves them onto the shelf at their finished value.

Inventory does not know what subcontracting is and does not learn it here: it takes a location. Deciding WHICH location belongs to whoever knows why the goods arrived.

Source

pub async fn repost_purchase_receipt( &self, id: Uuid, sink: &dyn GlPostSink, ) -> Result<SubmitOutcome, InventoryError>

Re-emit the GL post for a voucher whose physical movement committed but whose post is pending or failed (a transient accounting outage, or a crash between commit and the status update). This is the exit from a stuck failed voucher (council 2026-07-04) — without it, (submitted, failed) is terminal and the subledger silently stops tying to the GL.

Idempotent against the “physically-posted-but-status-not-updated” crash window: it rebuilds the SAME envelope (source_id = voucher_id), and accounting dedupes on (company, source_type, source_id, posting_type) — so a re-emit of an already-posted voucher returns the original journal, never a second one. An already-posted voucher short-circuits (returns the recorded ids); not_applicable is a no-op. Rebuilds the envelope from the stored header (never re-touches the SLE/Bin — the physical movement already happened).

Source§

impl InventoryWriteService

Source

pub async fn create_delivery_note( &self, d: NewDelivery, ) -> Result<Uuid, InventoryError>

Source

pub async fn submit_delivery_note( &self, id: Uuid, sink: &dyn GlPostSink, ) -> Result<SubmitOutcome, InventoryError>

Submit the goods-out voucher. Every line mints ONE stock move through the converged engine (the warehouse’s stock location → the customer location): confirm → assign (reserves against the source quants — the door refuses a line the reservation cannot cover WHOLE, preserving the voucher’s all-or-nothing availability posture) → done, which releases the reservation, draws the source quant, reblends the Bin (cogs = qty·rate; rate unchanged; residual flush when the bin drains to 0) and mints the SLE row. The voucher keeps its identity verbatim — header status + per-line COGS snapshot, the ONE Dr COGS · Cr Inventory envelope, the posting_state/repost machinery, the StockDelivered event; the moves post no GL (empty directive + the door-owned-GL tripwire sink).

Not cross-move atomic (each engine verb commits its own transaction): a crash mid-way leaves the delivery draft with some line moves landed — the deterministic move names ({delivery_number}/{seq}, origin = the delivery number) make a re-submit RESUME instead of double-shipping. A refusal mid-way (a line the reservation cannot cover) unreserves that line’s move and leaves the voucher draft: no stock moved, no reservation held.

Source

pub async fn repost_delivery_note( &self, id: Uuid, sink: &dyn GlPostSink, ) -> Result<SubmitOutcome, InventoryError>

Source§

impl InventoryWriteService

Source

pub async fn create_picking( &self, p: NewPicking, ) -> Result<PickingCreated, InventoryError>

Mint a picking: insert the transfer header, then mint one DRAFT move per line through the engine and confirm each (the operation type’s reservation posture fires with confirm — at_confirm reserves immediately). Every mint/confirm REPROJECTS the transfer (the engine does it on every move change — this method never touches transfers.state). Guards: R3 (name unique — the typed duplicate error), R9 (source != destination), non-empty, non-negative demand.

Not cross-move atomic: each engine verb commits its own transaction. A failure mid-way leaves the transfer projected at whatever its minted moves say (typically draft/confirmed) — a probe-able, retryable state, never a half-flipped stock position (stock only moves on validate_picking).

Source

pub async fn fetch_picking( &self, transfer_id: Uuid, ) -> Result<(TransferHeaderRow, Vec<MoveStateRow>), InventoryError>

The projection PROBE: read the transfer header (with its projected state) and the member move states. The state is a stored compute the engine re-derived — callers read it, they never assert it. The read rides the caller’s ambient org scope (ADR-0029): under the composed shape the decorator’s fence bounds it; undecorated (module tests, jobs) it is plain.

Source

pub async fn assign_picking( &self, move_id: Uuid, ) -> Result<PickingAssignment, InventoryError>

_assign_picking: attach a rule-launched move to its grouping transfer — the hop that carries a demand launched through the procurement engine (run_procurement / _run_pull mint moves with no transfer) onto the picking surface an operator validates. The move’s RULE names the operation type; the group key is (operation type, source, destination, partner, origin) with origin standing in for the procurement group — every move launched for one source document joins ONE transfer, and a transfer stays open for later lines of the same document. An open transfer that matches is joined; otherwise a header is minted (name from the operation type’s reference prefix, unique within the composing tenant’s scope; shipping policy inherited from the operation type). The projection then re-derives from the member move states, exactly as it does on every move change.

Idempotent: a move that already belongs to a transfer returns it (minted: false). Fail-closed on a move with no procurement rule (voucher-door moves keep their voucher identity — their door mints the moves and owns the GL, and no picking is derived for them here) and on terminal states (done / cancel never re-group).

Source

pub async fn validate_picking( &self, transfer_id: Uuid, gl: &MoveGlDirective, sink: &dyn GlPostSink, ) -> Result<PickingValidated, InventoryError>

button_validate (spec §2): _action_done over the transfer’s moves — nothing else. Done/cancelled member moves are skipped (idempotent re-validate). For each live move: the quant surface at its source grain is healed if the stock predates the converged model (Bins without quants); unreserved internal moves get an assign pass first (it mints the reservation mirror lines), and a move still without lines — nothing reservable, or an inbound move whose source is virtual — gets its demand line minted as the physical detail row so done has lines (R24); _action_done then flips the quants, mints the V7-ordered SLE pair, and posts the GL leg the move’s shape calls for. The partial-validate backorder policy comes from the operation type (ask maps to creating the backorder — the non-interactive default of Odoo’s wizard; delayed creates it too but leaves its reservation to the scheduler’s assign sweep).

Posting a GL leg needs the composing service’s GlPostSink; a leg whose accounts the directive lacks is simply not posted (the physical movement is unaffected).

Source

pub async fn submit_transfer( &self, t: NewTransfer, ) -> Result<Uuid, InventoryError>

The warehouse-to-warehouse stock entry, converged: the voucher rows keep their exact identity (header, item lines, the StockMoved event, value-neutral no-GL posture), while each line’s physical/valuation legs are minted by the move pipeline — one move per line, confirmed, reserved against the source quants, validated. The engine’s valuation core produces the W1-proven arithmetic: the OUT leg valued at the source Bin’s pre-move average BEFORE the destination reblende (V7 ordering), the residual flush when a Bin drains to zero, value conserved across the pair.

Source§

impl InventoryWriteService

Source

pub async fn stage_quant_count( &self, item_id: Uuid, location_id: Uuid, counted_qty: Decimal, ) -> Result<StagedCount, InventoryError>

Stage a counted quantity on a quant (spec §5.2): the count is a LEVEL (the counted on-hand), staged as inventory_quantity with its stored diff compute (T4) and the inventory_quantity_set gate that Self::apply_inventory demands. Staging OVERWRITES any prior staging — the count is not a delta, so re-counting replaces the previous count. Guards: R24 (the quant holds no reservations), R13 (only internal locations are countable). A quant that does not exist yet is initialized at zero — the count surface exists even before any stock does.

Source

pub async fn apply_inventory( &self, selector: QuantSelector, gl: &MoveGlDirective, sink: &dyn GlPostSink, ) -> Result<AppliedCount, InventoryError>

Apply a staged count (spec §5.2 _apply_inventory): mint (or resume) the is_inventory move that reconciles the quant’s on-hand to the count, and validate it through the engine pipeline — the move is the ONE writer of the quant’s quantity; this method never touches it. Idempotent by construction:

  • nothing staged (gate down) → no-op;
  • on-hand already equals the count (a crash between the move’s commit and the staging consume, or offsetting activity) → consume the staging, mint nothing;
  • a live is_inventory move for the grain already exists (a crash mid-pipeline) → resume IT, never mint a second (the mint-once gate);
  • a move landed between the count and here → LOUD OutdatedCount (the staged diff no longer reconciles the count; re-stage against the new on-hand).

GL: with accounts in gl, the engine posts the adjustment leg per move (Dr Inventory · Cr Adjustment up / reversed down, idempotency key = move id); a directive without accounts posts nothing (the physical movement is unaffected) — the voucher path drives the door that way and posts its own single net envelope.

Source

pub async fn staged_counts( &self, location_id: Uuid, ) -> Result<Vec<StagedCountRow>, InventoryError>

The pending-count worklist at a location (the partial index WHERE inventory_quantity_set = true serves this read): every staged-but-unapplied count, with the stored diff compute. A probe — it derives nothing, writes nothing.

Source

pub async fn submit_reconciliation( &self, r: NewReconciliation, sink: &dyn GlPostSink, ) -> Result<Uuid, InventoryError>

Submit a physical-count voucher (converged onto the adjustment door). Document identity verbatim: header + item rows + the single value-diff GL envelope + the StockReconciled event. Physical: per line, the count stages on the warehouse stock location’s quant and applies through Self::apply_inventory — the minted is_inventory moves carry the SLE/Bin legs (voucher-type stock_entry, voucher id = the move id: the ledger contract is the append-only SLE + moving average, which the engine owns). The voucher’s GL leg posts exactly once (recon-keyed idempotency); the door is driven with a no-accounts directive so no per-move GL duplicates it.

Sequencing: the physical applications run FIRST, the voucher rows are recorded LAST — a failure mid-way leaves no half-written voucher (the same number can be re-submitted), and the door’s idempotency (gate consumed per applied line; fresh staging per unapplied line) makes the re-run converge instead of double-applying. Not atomic across lines: an applied line’s stock movement stays applied (the SLE is append-only truth); the retry re-stages every line against the then-current on-hand.

Source

pub async fn repost_reconciliation( &self, id: Uuid, sink: &dyn GlPostSink, ) -> Result<SubmitOutcome, InventoryError>

Re-drive the GL leg for a reconciliation whose physical movement committed but whose post is pending or failed, OR — the case this exists for — a net==0 recon that crashed between the voucher record and mark_not_applicable and is stuck in (submitted, pending). Mirrors the receipt/delivery repost: rebuilds from the stored header, never re-touches the physical movement (the door’s staging gate is consumed and the moves are done — the apply is a no-op, so a repost can never double-apply the counts).

net != 0 → re-emit the value-diff envelope (idempotent: accounting dedupes on (company, source_type, source_id, posting_type)); net == 0 → reconcile to not_applicable. Already-posted/not_applicable short-circuits via already_settled.

Source§

impl InventoryWriteService

Source

pub async fn create_batch( &self, name: String, is_wave: bool, user_id: Option<Uuid>, ) -> Result<BatchHeaderRow, InventoryError>

Mint a batch: insert the header (a draft grouping point). state starts at draft and is from here on ONLY ever written by the projection recompute — this method never touches it. Guards: R3-shaped org-scoped name unique (the typed duplicate error on collision).

Source

pub async fn fetch_batch( &self, batch_id: Uuid, ) -> Result<(BatchHeaderRow, Vec<BatchMemberRow>), InventoryError>

The projection PROBE: read the batch header (with its projected state) and its member pickings’ states, riding the caller’s ambient org scope (ADR-0029) — an out-of-scope batch reads as absent under the composition’s fence.

Source

pub async fn add_picking_to_batch( &self, batch_id: Uuid, picking_id: Uuid, ) -> Result<BatchHeaderRow, InventoryError>

Attach a picking to its batch. Guards (all typed, all service-side with the DB trigger as backstop — enforcement: both, ADR-0015):

  • the batch exists (absent under the ambient scope reads as NotFound),
  • the batch is non-terminal (done/cancel refuse — BatchTerminal),
  • the picking exists and is non-terminal (PickingTerminalForBatch — a done or cancelled picking cannot join a work list),
  • the picking belongs to no other batch (PickingAlreadyBatched — membership is one batch per picking). The write moves only the membership pointer and stamps the had_members discriminator; the projection recompute that follows derives the state. Returns the re-derived header (a READ of the projection).
Source

pub async fn remove_picking_from_batch( &self, batch_id: Uuid, picking_id: Uuid, ) -> Result<BatchHeaderRow, InventoryError>

Detach a picking from its batch. Removal is always allowed — including a done or cancelled picking (that is how a finished list gets cleaned up). Detaching the last member leaves an EMPTY batch, which the projection then auto-cancels (the SB-1 discriminator: a batch that has grouped work must not linger as a live work item once emptied). Returns the re-derived header after the removal.

Source§

impl InventoryWriteService

Source

pub async fn create_scrap( &self, s: NewScrap, ) -> Result<ScrapRow, InventoryError>

Mint a scrap order in draft. Nothing moves yet — the header records WHAT will be scrapped, where from, and where to. Guards: strictly positive quantity, a live internal source location, a resolvable scrap location. The name is minted SCRAP/<short-uuid> (org-scoped unique — the typed duplicate error on the rare collision).

Source

pub async fn fetch_scrap( &self, scrap_id: Uuid, ) -> Result<Option<ScrapRow>, InventoryError>

The probe: read one scrap header, riding the caller’s ambient org scope (ADR-0029).

Source

pub async fn process_scrap( &self, scrap_id: Uuid, gl: &MoveGlDirective, sink: &dyn GlPostSink, ) -> Result<ScrapProcessed, InventoryError>

Process a DRAFT scrap: mint the move, drive it to done through the engine, stamp the header. The full-GL form — the caller’s directive carries the accounts and the sink posts the envelope. The move is is_inventory (the engine’s adjustment leg shape: the directive’s adjustment_account_id is the scrap expense account) and scrapped (the engine’s marker for scrap-marked moves). A scrap lands WHOLE: the backorder policy is Never and a move that cannot fully reserve refuses loudly (you cannot scrap stock that is not there — R22).

Crash-window safe: the done-stamp’s state = 'draft' guard means exactly one process call closes the header; a crash after the move landed but before the stamp leaves the scrap re-processable, and the resume check below re-drives the SAME move instead of minting a second one.

Source

pub async fn process_scrap_deferred( &self, scrap_id: Uuid, ) -> Result<ScrapProcessed, InventoryError>

The HTTP-shaped process: the SAME physical movement (the move lands done, the quants flip, the SLEs mint), but the GL leg carries a no-accounts directive — the engine builds no envelope and the move’s posting stays not_applicable until a service-driven Self::repost_move_gl drives it with real accounts (the module’s standing deferred posture for GL-posting verbs on a bare route).

Source§

impl InventoryWriteService

Source

pub async fn cancel_purchase_receipt( &self, id: Uuid, sink: &dyn GlPostSink, ) -> Result<SubmitOutcome, InventoryError>

Cancel the goods-in voucher: per line, ONE reverse move (stock location → supplier location) minted with forced_value = money(qty·rate) — the exact value the inflow added — confirm → assign (reserves against the stock quants; the door refuses a line whose free availability cannot cover the WHOLE reversal) → done, which draws the source quant, reblends the Bin back to its pre-receipt state and mints the compensating SLE row. The voucher’s ONE reversal envelope (Dr GR/IR · Cr Inventory) is unchanged.

Not cross-move atomic (each engine verb commits its own transaction): a crash mid-way leaves the voucher submitted with some reverse moves landed — the deterministic names ({receipt_number}/REV/{seq}) make a re-cancel RESUME instead of double-reversing.

Source

pub async fn cancel_delivery_note( &self, id: Uuid, sink: &dyn GlPostSink, ) -> Result<SubmitOutcome, InventoryError>

Cancel the goods-out voucher: per line, ONE reverse move (the customer location → the stock location) minted with forced_value = cogs_amount — the EXACT value the outflow consumed (the whole remaining value for a drain-to-zero line) — confirm → assign (an external source’s supply is unconditionally available, so the full line is covered) → done, which materializes the stock quant, reblends the Bin back to its pre-delivery state and mints the compensating SLE row. The voucher’s ONE reversal envelope (Dr Inventory · Cr COGS) is unchanged. Always safe — qty only increases.

Source§

impl InventoryWriteService

The move lifecycle engine. An impl InventoryWriteService chunk over the vocabulary in super::inventory_write_service — the converged stock pipeline the routes/scheduler surfaces drive.

Source

pub async fn create_move(&self, m: NewStockMove) -> Result<Uuid, InventoryError>

Create a DRAFT move (spec §1: draft → waiting/confirmed happens on confirm, never at insert). Guards: R9 (src != dest), non-negative demand (R23 at the door), R13 (a quant surface can never be a view location — checked for both endpoints that hold stock).

Source

pub async fn action_confirm( &self, move_id: Uuid, ) -> Result<String, InventoryError>

draft → confirmed, or draft → waiting while any move_orig_ids parent is not done (spec §1: waiting is the state a chained move sits in until its parents land). procure_method gates supply: make_to_order / mts_else_mto moves are minted by the procurement (rule) engine, not here — this method only owns the state gate.

The move read rides the caller’s ambient org scope (ADR-0029): under the composed shape the decorator’s fence bounds it; undecorated (module tests, jobs) it is plain.

Source

pub async fn action_assign( &self, move_id: Uuid, ) -> Result<MoveAssignOutcome, InventoryError>

Reserve against quants at the source location (spec §1 _action_assign): the authoritative reserved_quantity is written under each quant’s FOR UPDATE (competing reservations serialize there — one winner per unit of stock, R22/R25), a mirror move-line is minted per reserved quant grain, and the move state aggregates the mirror.

The move read rides the caller’s ambient org scope (ADR-0029): under the composed shape the decorator’s fence bounds it; undecorated (module tests, jobs) it is plain.

Source

pub async fn unreserve_move( &self, move_id: Uuid, ) -> Result<Decimal, InventoryError>

Release every reservation the move holds (spec §1: cancel frees reservations first; assign retries also release-then-re.reserve). The mirror lines zero out; the authoritative reserved_quantity drops by exactly what the lines held.

The move read rides the caller’s ambient org scope (ADR-0029): under the composed shape the decorator’s fence bounds it; undecorated (module tests, jobs) it is plain.

Source

pub async fn action_done( &self, move_id: Uuid, backorder: BackorderPolicy, gl: &MoveGlDirective, sink: &dyn GlPostSink, ) -> Result<MoveDoneOutcome, InventoryError>

The mutation core (spec §4). See the module docs above for the full pipeline; the guards, the two-step quant sync, the V7-ordered valuation, the chain propagation, the backorder split and the projection all live here.

The move read rides the caller’s ambient org scope (ADR-0029): under the composed shape the decorator’s fence bounds it; undecorated (module tests, jobs) it is plain.

Source

pub async fn action_cancel( &self, move_id: Uuid, ) -> Result<Decimal, InventoryError>

* → cancel (spec §1): frees the reservation first, then propagates to the chained children (move_dest_ids) unless propagate_cancel=false — never into a done move.

The move read rides the caller’s ambient org scope (ADR-0029): under the composed shape the decorator’s fence bounds it; undecorated (module tests, jobs) it is plain.

Source

pub async fn repost_move_gl( &self, move_id: Uuid, gl: &MoveGlDirective, sink: &dyn GlPostSink, ) -> Result<SubmitOutcome, InventoryError>

Re-drive the GL leg of a done move whose posting_state is pending or failed — a rejected or interrupted AccountingPost from _action_done. The physical movement (quants, Bin, SLE rows) already happened and is never re-touched: the envelope is rebuilt from the move’s committed ledger legs plus the caller’s account directive, re-emitted under the move’s ORIGINAL source identity (source_type='inventory', source_id = move id, posting_type='original'), and accounting’s dedupe on that identity makes the re-drive idempotent — a leg that actually landed before the status write was lost returns the original journal instead of a second one.

Short-circuits exactly like the voucher doors’ repost verbs: posted → nothing to drive; not_applicable → this move owns no GL leg (a voucher door posted its voucher’s envelope; a value-neutral shape posts nothing), so a sweep can call this blindly. If the rebuilt envelope is None (the directive no longer supplies the accounts this leg shape needs), the unsettled leg retires to not_applicable — the GL is genuinely not postable under the current configuration and the move leaves the sweep worklist.

On a fresh rejection the move parks in failed again and the error surfaces, as in _action_done.

The move read rides the caller’s ambient org scope (ADR-0029): under the composed shape the decorator’s fence bounds it; undecorated (module tests, jobs) it is plain.

Source§

impl InventoryWriteService

Source

pub async fn create_landed_cost( &self, lc: NewLandedCost, ) -> Result<Uuid, InventoryError>

Open a DRAFT landed cost: header + cost lines as one unit. Guards: at least one line (nothing to allocate); every line carries a credit account (a line without one is rejected loudly — its split’s credit side would be undefined). Negative amounts are allowed: a negative landed cost is the reversal pattern.

Source

pub async fn validate_landed_cost( &self, lc_id: Uuid, sink: &dyn GlPostSink, ) -> Result<SubmitOutcome, InventoryError>

Validate the DRAFT landed cost: split → revalue → post, the full verb. The physical revaluation (worksheet rebuild + value-only SLE rows + bin reblends + state=done + GL leg armed pending) commits FIRST; the GL post is eventually consistent, exactly like the voucher doors. Service/job-driven (it needs the composing service’s GlPostSink).

Source

pub async fn validate_landed_cost_deferred( &self, lc_id: Uuid, ) -> Result<SubmitOutcome, InventoryError>

The HTTP-shaped validate: the SAME physical revalidation, but the GL leg stays ARMED pending for a service-driven Self::repost_landed_cost to drive (the composing service’s sink is not available on a bare route — the module’s standing posture for GL-posting verbs). Documents that structurally post nothing (a periodic valuation policy, an all-consumed allocation) retire to not_applicable immediately.

Source

pub async fn cancel_landed_cost( &self, lc_id: Uuid, ) -> Result<(), InventoryError>

Cancel a DRAFT landed cost. A done landed cost can never cancel — its bins and ledger already revalued; the correction pattern is a NEGATIVE landed cost (swapped legs).

Source

pub async fn repost_landed_cost( &self, lc_id: Uuid, sink: &dyn GlPostSink, ) -> Result<SubmitOutcome, InventoryError>

Re-drive the GL leg of a DONE landed cost whose posting_state is pending or failed (a rejected or interrupted post — the physical revaluation already committed and is never re-touched). The envelope is rebuilt from the MINTED ledger and the worksheet: debit legs from the landed-cost SLE rows (each row’s signed delta, its target line resolving the valuation-account chain), credit legs from the worksheet’s per-cost-line shares scaled by each row’s snapshotted remaining share (a done move’s quantity is frozen, so the rebuild is exact). Idempotent: posted short-circuits with the recorded ids, not_applicable is a no-op, and the envelope re-uses the document’s source identity so accounting’s dedupe on (company, source_type, source_id, posting_type) can never double-post.

Trait Implementations§

Source§

impl Clone for InventoryWriteService

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl MovePipeline for InventoryWriteService

The write service IS the move engine, so it implements the port the daily scheduler drives (procurement_service::MovePipeline): the per-move confirm/assign verbs on the CALLER’S connection — the scheduler runs them inside its per-batch transaction, so a batch’s transitions commit or roll back together. Failures cross the boundary as a flat {code, message} (the engine’s own error taxonomy stays on this side of the port). Events publish immediately through the advisory sink; the batch commit boundary is the scheduler’s concern.

Source§

fn confirm<'life0, 'life1, 'async_trait>( &'life0 self, conn: &'life1 mut PgConnection, move_id: Uuid, ) -> Pin<Box<dyn Future<Output = Result<MoveState, MovePipelineError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Source§

fn assign<'life0, 'life1, 'async_trait>( &'life0 self, conn: &'life1 mut PgConnection, move_id: Uuid, ) -> Pin<Box<dyn Future<Output = Result<MoveState, MovePipelineError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more