Mango.Nop.Plugins/Nop.Plugin.Misc.AIPlugin/docs/MEASUREMENT.md

113 lines
7.2 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Measurement Workflows
> Part of `Nop.Plugin.Misc.FruitBankPlugin`. See `README.md` for project overview.
> For entity model see `docs/DOMAIN_MODEL.md`.
> For SignalR endpoints see `docs/SIGNALR/README.md`.
> For core measurement system rules and common domain traps, see: `../../../../../FruitBankHybridApp/FruitBank.Common/docs/GLOSSARY.md`
Three parallel measurement workflows share the same weight formula and `MeasuringStatus` lifecycle.
## Shared concepts (canonical in DOMAIN_MODEL.md)
These are defined once in [`DOMAIN_MODEL.md`](DOMAIN_MODEL.md) — referenced here, not duplicated:
- **Weight formula** — `NetWeight = GrossWeight PalletWeight (TrayQuantity × TareWeight)`. See [DOMAIN_MODEL.md § Weight Formula](DOMAIN_MODEL.md#weight-formula) for field meanings and edge cases.
- **MeasuringStatus lifecycle** — `NotStarted (0) → Started (10) → Finnished (20) → Audited (30)`. See [DOMAIN_MODEL.md § MeasuringStatus Lifecycle](DOMAIN_MODEL.md#measuringstatus-lifecycle) for state transitions. Note: `Finnished` is an intentional double-n typo — do not "fix" it.
- **IsMeasurable Flag** — `ProductDto.IsMeasurable` master toggle for weight validation. See [DOMAIN_MODEL.md § IsMeasurable Flag](DOMAIN_MODEL.md#ismeasurable-flag) for `false`-branch semantics.
## Workflow 1: Inbound Shipping
Supplier truck arrives at the warehouse. Goods are weighed and compared to the delivery document.
```
Shipping (truck)
→ ShippingDocument (supplier delivery note)
→ ShippingItem (product line)
→ ShippingItemPallet (individual measurement)
```
### Flow
1. **Create Shipping** — truck registration (LicencePlate, ShippingDate, CargoCompany)
2. **Add ShippingDocument** — link to Partner (supplier), upload PDF delivery note
3. **Add ShippingItem** — product line from document. `IsMeasurable` copied from `ProductDto.IsMeasurable`
4. **Weigh pallets**`FruitBankDataController.AddOrUpdateMeasuredShippingItemPallet()`
- Each pallet: GrossWeight, PalletWeight, TareWeight, TrayQuantity → NetWeight (formula in Shared concepts above)
5. **Cascade update** — after each pallet measurement:
- `ShippingItem`: MeasuredGrossWeight, MeasuredNetWeight, MeasuredQuantity recalculated from pallets
- `ShippingDocument.IsAllMeasured` = all items measured
- `Shipping.IsAllMeasured` = all documents measured
- Product `AverageWeight` updated from measured data
### Event Cascade (FruitBankEventConsumer)
```
ShippingItemPallet deleted → ShippingItem measuring values refreshed
ShippingItem inserted/updated → ShippingDocument.IsAllMeasured rechecked
ShippingDocument inserted/updated → Shipping.IsAllMeasured rechecked
Shipping deleted → cascade delete ShippingDocuments
ShippingDocument deleted → cascade delete ShippingItems
ShippingItem deleted → cascade delete ShippingItemPallets
```
### ShippingItem: Declared vs Measured
| Declared (from document) | Measured (warehouse) | Discrepancy tracked |
|---|---|---|
| `QuantityOnDocument` | `MeasuredQuantity` | Yes |
| `GrossWeightOnDocument` | `MeasuredGrossWeight` | Yes |
| `NetWeightOnDocument` | `MeasuredNetWeight` | Yes |
## Workflow 2: Outbound Order
Customer order is prepared. Items are weighed before dispatch.
```
OrderDto (order)
→ OrderItemDto (line item)
→ OrderItemPallet (measurement record)
```
### Flow
1. **Start Measuring**`CustomOrderSignalREndpoint.StartMeasuring(orderId, userId)`
- Sets `MeasurementOwnerId` via GenericAttribute
- Order status set to Processing, Payment to Pending
- Broadcasts `SendOrderChanged`
2. **Weigh pallets**`CustomOrderSignalREndpoint.AddOrUpdateMeasuredOrderItemPallet()`
- Same weight formula as shipping
- Triggers price recalculation after each pallet
- Broadcasts `SendOrderItemPalletChanged`
3. **Complete order**`CustomOrderSignalREndpoint.SetOrderStatusToComplete(orderId, revisorId)`
- Validates: all order items must have pallets
- Recalculates final prices v<>!I<><49>e<EFBFBD><76>q <03>|<7C><>-<2D><><EFBFBD><07>0
.񈳂 `8à p<>ʳ<EFBFBD>B<EFBFBD>0 <04>à<EFBFBD>800<30>Ha@@À l<><6C>!!Aa<14> G<>p <08>c<EFBFBD> k<><6B><EFBFBD>
<EFBFBD> <06><02>G<EFBFBD>j<EFBFBD><6A><EFBFBD>J<EFBFBD>.W<><57>B<EFBFBD>E<EFBFBD>Tz<54><7A><EFBFBD><0F><>z<EFBFBD>2g<32><04>xeF<65><46><EFBFBD>H<EFBFBD>0<EFBFBD><30><EFBFBD>h)<29>!<04>J<<3C> ew<><77><EFBFBD>0 *<2A><>B`` <00>p`,f<>I<EFBFBD><49><EFBFBD>` DC<12>\(<28>H<EFBFBD>B<EFBFBD>p<03>@p(dq<64> PB<><42>.<2E><08><><EFBFBD>@ <02>pjqJ<71>C <20>@F<><46>@.<2E><08>!`  <0C><><EFBFBD>0paʗ<61><CA97>`P,"<22><><EFBFBD>!<21>,.<2E>H<02>0D Pl<>
*E<>`($<04>`0 .<2E>Ȝ<EFBFBD>a`@<04><>`0f<><66><EFBFBD><EFBFBD><02>((<02> ,<2C>Ȁ<EFBFBD><C880>00<02><><EFBFBD>`0j<><6A><EFBFBD><EFBFBD> <20>0 <05>p(,<2C><>"<01>@<02>@p0j<>J<EFBFBD><4A><EFBFBD>@   *<EFBFBD><08><><EFBFBD>`<03> ``<EFBFBD><EFBFBD>3<EFBFBD><EFBFBD>@8<04><>@p@<>  8<03>18f<>J<02>`<01> *ሚA<E1889A>` A<> fQ<66><16>"a@ <04>Dbp@(*<EFBFBD><EFBFBD> <01> 0d<><64><04><>P <07>@0 *<2A>Ȟ P<02><>@0j<><6A><EFBFBD>C<EFBFBD> A<>p8 .<01><01><> <01>@l<>J!Da8<04>B<EFBFBD>` <><D188><EFBFBD> <02>P d<>
<EFBFBD><EFBFBD><EFBFBD>p(
<05>!A,<2C>H0<48>a À` h<>ʙCA <00><>@A( 2<>HA<>p8
<EFBFBD><EFBFBD><02>Ph<><68>#Aa<41>@<0E><>,<2C>ȏBaP( <0C><><EFBFBD>0la<6C><1B>"<22>X8
<02>A880<11> B<>0(@ P0h<>J<EFBFBD><04><><0E>€2<><08><>`<60>@<10>"<22>l<>ʻ<EFBFBD><CABB>PH <02>Ba00<>ȭ<EFBFBD><C8AD> H
<EFBFBD><EFBFBD>a8n<><6E>6<EFBFBD>A1X
C!!H2<>ȇ<EFBFBD>aP<06>a<EFBFBD>8(p<>J <09><01>8 8.<11><>@``  <0C>Ba@ p<><70>D<>P,E<><45>@6<11><><02>P8
C<>@0r a 
<08><>P80! <02><>`
<02>`@(tK<><4B>a@
<EFBFBD>a 6!<21><><02>00<02><01><00><><EFBFBD>=<02>p<10>C<>8 8A<38><02>0 <04><> x 1C` (<07><>`02!<21><01>P( <0C><><EFBFBD>P8x!<21><><EFBFBD>`pH
<04>P8 2A<32><41>Aa <00> <08>A<EFBFBD><08>"C<>`@2QɞA<C99E>0<06>@` t<>
=<03>p0 <0C>A<EFBFBD><41>0L! <09><><EFBFBD><EFBFBD>X<04><><EFBFBD>H<14><>ʤ<EFBFBD>E<03>,
<EFBFBD>A<EFBFBD>PD:!<21><><01>p C<01>($<24>A<EFBFBD><13><02>(<04><>"q$4A<34><17>aP@(<14>q <05>0<00><><EFBFBD>0P<񈇁B<EFBFBD>h4<16><04><>h,<2C>1<EFBFBD> Bq`<16><><EFBFBD><11><>!<21><><04><>H <05>@(<14><01><12> <10>C<EFBFBD>`<12>K<EFBFBD>p <0E><02>Dm<44>پ<EFBFBD><D9BE>K  B<>4$*<2A><>R<EFBFBD>ń<<EFBFBD><EFBFBD>E<EFBFBD>.:?R<><52><EFBFBD><EFBFBD>E<EFBFBD>&<EFBFBD>f<EFBFBD>20<><:<EFBFBD>z<EFBFBD> <RI<EFBFBD><EFBFBD>z1<EFBFBD><EFBFBD>AIT
<EFBFBD><EFBFBD><EFBFBD>Ty0!<02>ʂ `8(41<34>0yd<79>HR<48>
<EFBFBD>`@0<`H<EFBFBD>r<EFBFBD>L<EFBFBD>>T<EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><46><C8A6>zQ<7A>̋10<10>_X<5F><58><EFBFBD><EFBFBD><04>Gq<><71>P<EFBFBD>e<11><>U<EFBFBD><55><EFBFBD><EFBFBD>Q<>tN <20><><EFBFBD><EFBFBD>
<EFBFBD>%<25>^[<5B>V[<5B>f<EFBFBD><66>l<EFBFBD>;<3B>\ <0C><><EFBFBD>(F f 
<EFBFBD><EFBFBD>,~2"<22>߅<03><><EFBFBD>P<EFBFBD><50>H3<48>d8<11><>G<EFBFBD><47><EFBFBD><EFBFBD>f<EFBFBD>
ȴ<EFBFBD>T.*<2A>`h<>h@6<> &<EFBFBD>Al./<2F><><EFBFBD><EFBFBD>|4<>Ȥ<14>x:5<><35>m<EFBFBD><03><>F,<2C><18>@%n<><6E>'r94d <0C><>p|D<>ymeP<65>R<EFBFBD><52> qJ<71><4A>-<2D>$<24><><EFBFBD>N<EFBFBD><4E><EFBFBD><EFBFBD>p@,<2C><><1D><>SYf<16><><EFBFBD>Y<10><>,<2C><><13>p:%Ke<4B>X, <20>$<24><><EFBFBD>u <03>(<28><>`<60>
<EFBFBD> 2 <09><> <20>J<EFBFBD>c<EFBFBD>p.n3L<33>o<><6F><EFBFBD><EFBFBD>x: <0C><>(`<60>R<<1C>z<EFBFBD><7A><EFBFBD>V<EFBFBD>ܡ:<3A><><EFBFBD><EFBFBD>rq<72>Zäen- <20><>~<7E><><EFBFBD><EFBFBD>><3E><><EFBFBD><16>m
<EFBFBD><EFBFBD>ɇ`cC<1A>v<EFBFBD><76><EFBFBD><EFBFBD><EFBFBD>$ <06>i<EFBFBD><69><EFBFBD>˄ <09><>#qH<02><>a0*B <0B>p<EFBFBD>h$<07><>`h <1C><><EFBFBD><EFBFBD> 6<>F<1F><>:<3A>D<EFBFBD>t<EFBFBD><74><EFBFBD><EFBFBD><EFBFBD>z<EFBFBD>O<EFBFBD><4F>'[<5B>TԁM?<3F><>8 <02><><EFBFBD>00@<40>Ñ1,<1E>ƀ<EFBFBD>yh<79>
<EFBFBD>F<EFBFBD><EFBFBD><EFBFBD>8E`4<><34>Դh<><68>x2 <09><>AXP<58><50> <0C><05>p`,
a<> 4<><02> O<><4F>pd0O<><11>(<28>A<EFBFBD>A<>P <04>q<1C>2UBP<42><14>K#<02>\<5C><>
<EFBFBD>D<EFBFBD>P$<16><>"<22>h <1C><><03>CBhP"<22><>R<>x<EFBFBD>!<03>@Y,<05><>q@<<<03>&<EFBFBD>!PX(<08>AdD<>Q<EFBFBD>AA0$<16><>C1 <ӗ3<EFBFBD>e2<EFBFBD>(0<EFBFBD><EFBFBD>ñT<EFBFBD>!<0E><>d<EFBFBD>h0<0F><><EFBFBD>xB<EFBFBD><EFBFBD><EFBFBD><04><> 8<1A>D<EFBFBD><EFBFBD>`<18>A<EFBFBD><EFBFBD><00>Q $<07>r`HN<EFBFBD>X<01>"$<24>I<EFBFBD><EFBFBD>(0<02>N<EFBFBD><EFBFBD>B<EFBFBD>h
<EFBFBD>@<40><>,LS<18><>%<25><>h8<EFBFBD>J$3X<EFBFBD><EFBFBD>&<26><>P
<EFBFBD>EAqj#ٛ<EFBFBD><EFBFBD><EFBFBD>p8&<11>g<EFBFBD><EFBFBD>l<EFBFBD><EFBFBD><EFBFBD><04>ap
<EFBFBD><EFBFBD>A<EFBFBD>8 lS<EFBFBD>
<EFBFBD><EFBFBD>`,"<22>ƅ<03>\<5C>Ošp0(<04><>aqPh<03>&L<EFBFBD>r<EFBFBD><"
цs ]<02><0E><>bpP8<0E><><EFBFBD><EFBFBD>p$h<03>D<EFBFBD>aJb<EFBFBD><EFBFBD>DbOA<EFBFBD>`X<07>!H <EFBFBD><05><><EFBFBD>L("<22><>S1R<EFBFBD><EFBFBD><EFBFBD>a0H,C<EFBFBD><EFBFBD><00><><EFBFBD><EFBFBD>ñ<EFBFBD>\
<EFBFBD>b<EFBFBD>Tb<0F>D<EFBFBD>A80<10>Ca<EFBFBD>@8<EFBFBD>cZ.<2E>E<EFBFBD><EFBFBD>p0
<EFBFBD><EFBFBD>3<EFBFBD>HRϣE`<60>@,
<EFBFBD><EFBFBD>pP$<24><>Z<EFBFBD>GaA8<1E><>d"y<14><><0E><>2)D<13><04>P <EFBFBD><1A>ʠ<EFBFBD><EFBFBD>0*c<EFBFBD><EFBFBD>
O<1C>A<EFBFBD>(@
b@ <08><><EFBFBD>=F<EFBFBD>"YD <EFBFBD><EFBFBD><EFBFBD>(<28><>a9I$<24>H(
<08><>Z<EFBFBD><16><>7<EFBFBD><EFBFBD>v7ݍ<EFBFBD>r <EFBFBD>c<EFBFBD>ƀ00$"<22>\<5C><EFBFBD>~<12><>@ <<+_<EFBFBD>Y<EFBFBD><EFBFBD><EFBFBD>.<2E> t8
<EFBFBD>T & <16>l<13><><EFBFBD>T<1F>"@ <00>Q<EFBFBD>F<EFBFBD><EFBFBD>H$ <EFBFBD><EFBFBD><EFBFBD>0H<EFBFBD><EFBFBD> <EFBFBD>X,<02>D<EFBFBD><EFBFBD>t܁<EFBFBD><07><>p<04>H<EFBFBD><EFBFBD>xTS<EFBFBD>`<60>`,<16>ɦsB<EFBFBD><EFBFBD>a΂E<EFBFBD>PE!<21><>( <EFBFBD>Cs<EFBFBD>D& H<EFBFBD>CI<EFBFBD><EFBFBD><EFBFBD> (<28>(s<EFBFBD>\(<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>L6CT<EFBFBD>T<EFBFBD><EFBFBD><EFBFBD>f<EFBFBD>IB<EFBFBD><EFBFBD><EFBFBD>4<04><> A@`<60><><EFBFBD>#y46<EFBFBD><EFBFBD><15>G<EFBFBD><10>q<EFBFBD>c<EFBFBD>8M><EFBFBD><EFBFBD><EFBFBD>c
<EFBFBD>t*]<0E><>&<EFBFBD>(<00><>
<EFBFBD>~<><7F><EFBFBD>U#D9 r<>A<EFBFBD><41>Z<11>F<EFBFBD><46><EFBFBD>0*<2A>c<EFBFBD>5a"<22><05><><EFBFBD><EFBFBD>A(Ȕ҃<>&<EFBFBD><EFBFBD>p:<3A><><EFBFBD>4><3E>t<EFBFBD><74>õ<17>B<EFBFBD><42><EFBFBD>X<EFBFBD><58><EFBFBD><EFBFBD><EFBFBD>3܁<33><DC81>Ѹx*<2A>І<EFBFBD><D086><00><>kƁA<C681>d<1C><>&<EFBFBD><EFBFBD>l,<2C>#<23><>ZN<5A><4E>6<>ь<EFBFBD>s͛}<7D><><0F>r 2<><32><EFBFBD><EFBFBD><EFBFBD>Z<>v[<5B>><3E><><EFBFBD><EFBFBD><EFBFBD>l<12><>*|Ng˹J$<24><><EFBFBD>p#N<><19>,<2C><>8<11>ti R5<19>Ч<EFBFBD><D0A7>n(N<>SQr<><72> mc<6D>D<04>@00$<24><>V<EFBFBD><56><EFBFBD><EFBFBD>`<1C><><EFBFBD><16> <0B>T<EFBFBD><54>!<21>2̈́A@<14>"
<<13>
y=<3D>+<14>p*h<>ɖ<EFBFBD><C996> <02>dR<64>L<EFBFBD><61>Q<>D<04> V#<23>`q <09>ˤ<EFBFBD><06><><EFBFBD>` ڱ<>(<28>̅ B @X$J<> <09><><EFBFBD>
<03><00><><EFBFBD><EFBFBD><05><>`P$F<><46>VQ <05>p <02>A<>X<14>A <17>"r8<10>B<02>q8<71><38>I@ $<24>$sX$"<22><15>  (L<>g<EFBFBD>:<3A>f<EFBFBD>ϼ<EFBFBD><CFBC>|<7C>