use v6;
# data exchange types
class PO-Expin-Item is rw {...}
class PO-Expin is rw {
has Str ($.customer, $.po-ref, $.notes, $.total-value, $.total-quantity);
has PO-Expin-Item @.items;
}
class PO-Expin-Item {
has Str ($.po-ref, $.sku, $.description, $.value);
has $.quantity where * ~~ Int|IntStr;
}
# domain data types
class LineItem is rw {...}
class PurchaseOrder is rw {
has (Str $.customer, Str $.order-number, Str $.remarks, Numeric $.total-price, Numeric $.total-quantity, LineItem @.items);
}
class LineItem {
has (Str $.order-number, Str $.part-number, Str $.description, Numeric $.price, Int $.quantity);
}
# prototype order processor does generic mapping, then delegates to customer specific sub for custom mapping
proto sub process-order (PO-Expin $*expin, |) returns PurchaseOrder {
my PurchaseOrder $*po .= new: :customer(.customer),
:order-number(.po-ref),
:remarks(.notes),
:total-price( .total-value.defined ?? .total-value.Rat !! Nil ),
:total-quantity( .total-quantity.defined ?? .total-quantity.Int !! Nil )
given $*expin;
$*po.items = map { process-item($_, $*expin.customer) }, $*expin.items;
{*} # custom order-level code
$*po;
}
# Nordstrom Expin sub-type means customer is NORDSEA
subset NordstromExpin of PO-Expin where *.customer eq 'NORDSEA';
# dispatch to this customization if this order expin belongs to Nordstrom
# replaces {*} in proto sub process-order when the customer is NORDSEA
multi sub process-order (NordstromExpin $*expin) {
$*po.total-quantity = $*po.items>>.quantity>>.Int.sum;
$*po.total-price = $*po.items>>.price>>.Rat.sum;
}
subset NikeExpin of PO-Expin where *.customer eq 'NIKEPDX';
multi sub process-order (NikeExpin $*expin) {
$*po.total-price = $*po.items>>.price>>.Rat.sum + 100.0; # $100 shop fee per order
$*po.total-quantity = $*po.items>>.quantity>>.Int.sum;
$*po.remarks.=uc; # all NIKE descriptions are uppercase
}
# prototype item processor does generic line item mapping, then dispatches to customer specific mapping
proto sub process-item ( PO-Expin-Item $*item, Str:D $ ) returns LineItem {
my LineItem $*line-item .= new(
order-number => .po-ref,
part-number => .sku,
description => .description,
price => .value.Rat,
quantity => .quantity.Int
) given $*item;
{*} # custom item-level code
$*line-item;
}
# customer specific item processing (replaces {*} in proto sub process-item when the customer is NORDSEA)
multi sub process-item (PO-Expin-Item $*item, 'NORDSEA') {
$_ *= 10 given $*line-item.price
}
multi sub process-item (PO-Expin-Item $*item, 'NIKEPDX') {
$*line-item.description.=uc; # all NIKE descriptions are uppercase
}
my $nordstrom-po-ref = '572242';
my PO-Expin $nordstrom-expin = new PO-Expin:
customer => 'NORDSEA',
:$nordstrom-po-ref,
notes => 'this is a purchase order',
items => [
PO-Expin-Item.new(
po-ref => $nordstrom-po-ref,
sku => 'sku1',
description => 'first PO item',
value => '20',
quantity => 5
),
PO-Expin-Item.new(
po-ref => $nordstrom-po-ref,
sku => 'sku2',
description => 'second PO item',
value => '35',
quantity => 5
),
PO-Expin-Item.new(
po-ref => $nordstrom-po-ref,
sku => 'sku3',
description => 'third PO item',
value => '16',
quantity => 5
),
];
my $nike-po-ref = 'NIKE-REF';
my PO-Expin $nike-expin = new PO-Expin:
customer => 'NIKEPDX',
po-ref => $nike-po-ref,
notes => 'this is a NIKE purchase order',
items => [
PO-Expin-Item.new(
po-ref => $nike-po-ref,
sku => 'nike1',
description => 'first NIKE PO item',
value => '41',
quantity => 11
),
PO-Expin-Item.new(
po-ref => $nike-po-ref,
sku => 'nike2',
description => 'second NIKE PO item',
value => '32',
quantity => 17
),
PO-Expin-Item.new(
po-ref => $nike-po-ref,
sku => 'nike3',
description => 'third NIKE PO item',
value => '14',
quantity => 502
),
];
my PurchaseOrder $nordstrom-po = process-order $nordstrom-expin;
$nordstrom-po.gist.say;
my PurchaseOrder $nike-po = process-order $nike-expin;
$nike-po.gist.say;