1 package SL::PriceSource::Base;
 
   5 use parent qw(SL::DB::Object);
 
   6 use Rose::Object::MakeMethods::Generic (
 
   7   scalar => [ qw(record_item record) ],
 
  10 sub name { die 'name needs to be implemented' }
 
  12 sub description { die 'description needs to be implemented' }
 
  14 sub available_prices { die 'available_prices needs to be implemented' }
 
  16 sub available_discounts { die 'available_discounts needs to be implemented' }
 
  18 sub best_price { die 'best_price needs to be implemented' }
 
  20 sub best_discounts { die 'best_discounts needs to be implemented' }
 
  22 sub price_from_source { die 'price_from_source needs to be implemented:' . "@_" }
 
  25   $_[0]->record_item->part;
 
  29   $_[0]->record->is_sales ? $_[0]->record->customer : $_[0]->record->vendor;
 
  40 SL::PriceSource::Base - this is the base class for price source adapters
 
  44   # working example adapter:
 
  45   package SL::PriceSource::FiveOnEverything;
 
  47   use parent qw(SL::PriceSource::Base);
 
  49   # used as internal identifier
 
  52   # used in frontend to signal where this comes from
 
  53   sub description { t8('Simple') }
 
  55   my $price = SL::PriceSource::Price->new(
 
  57     description  => t8('Only today 5$ on everything!'),
 
  58     price_source => $self,
 
  61   # give list of prices that this
 
  62   sub available_prices {
 
  70   sub price_from_source {
 
  76 See L<SL::PriceSource> for information about the mechanism.
 
  78 This is the base class for a price source algorithm. To play well, you'll have
 
  79 to implement a number of interface methods and be aware of a number of corner
 
  82 =head1 AVAILABLE METHODS
 
  90 C<record> can be any one of L<SL::DB::Order>, L<SL::DB::DeliveryOrder>,
 
  91 L<SL::DB::Invoice>, L<SL::DB::PurchaseInvoice>. C<record_item> is of the
 
  92 corresponding position type.
 
  94 You can assume that both are filled with all information available at the time.
 
  95 C<part> and C<customer>/C<vendor> as well as C<is_sales> can be relied upon. You must NOT
 
  96 rely on both being linked together, in particular
 
  98   $self->record_item->record   # don't do that
 
 100 is not guaranteed to work.
 
 102 Also these are copies and not the original documents. Do not try to change
 
 103 anything and do not save those.
 
 107 Shortcut to C<< record_item->part >>
 
 109 =item C<customer_vendor>
 
 111 Shortcut to C<< record->is_sales ? record->customer : record->vendor >>
 
 115 =head1 INTERFACE METHODS
 
 121 Must return a unique internal name. Must be entered in
 
 122 L<SL::PriceSource::ALL>.
 
 126 Must return a translated name to be used in the frontend. Will be used to
 
 127 distinguish the origin of different prices.
 
 129 =item C<available_prices>
 
 131 Must return a list of all prices that your algorithm can recommend to the user
 
 132 for the current situation. Each price must have a unique spec that can be used
 
 133 to recreate it later. Try to be brief, no one needs 20 different price
 
 136 =item C<available_discounts>
 
 138 Must return a list of all prices that your algorithm can recommend to the user
 
 139 for the current situation. Each discount must have a unique spec that can be
 
 140 used to recreate it later. Try to be brief, no one needs 20 different discount
 
 145 Must return what you think of as the best matching price in your
 
 146 C<available_prices>. This does not have to be the lowest price, but it will be
 
 147 compared later to other price sources, and the lowest will be set.
 
 149 =item C<best_discount>
 
 151 Must return what you think of as the best matching discount in your
 
 152 C<available_discounts>. This does not have to be the highest discount, but it
 
 153 will be compared later to other price sources, and the highest will be set.
 
 155 =item C<price_from_source SOURCE, SPEC>
 
 157 Must recreate the price or discount from C<SPEC> and return. For reference, the
 
 158 complete C<SOURCE> entry from C<record_item.active_price_source> or
 
 159 C<record_item.active_discount_source> is included.
 
 161 Note that constraints from the rest of the C<record> do not apply anymore. If
 
 162 information needed for the retrieval can be deleted elsewhere, then you must
 
 165 If the price for the same coditions changed, return the new price. It will be
 
 166 presented as an option to the user if the record is still editable.
 
 168 If the price is not valid anymore or not reconstructable, return a price with
 
 169 C<price_source> and C<spec> set to the same values as before but with
 
 170 C<invalid> or C<missing> set.
 
 174 =head1 TRAPS AND CORNER CASES
 
 180 Be aware that all 8 types of record will be passed to your algorithm. If you
 
 181 don't serve some of them, just return empty lists on C<available_prices> and
 
 186 Information in C<record> might be missing. Especially on newly or automatically
 
 187 created records there might be fields not set at all.
 
 191 Records will not be calculated. If you need tax data or position totals, you
 
 192 need to invoke that yourself.
 
 196 Accessor methods might not be present in some of the record types.
 
 200 You do not need to do price factor and row discount calculation. These will be
 
 201 done automatically afterwards. You do have to include customer/vendor discounts
 
 202 if your price interacts with those.
 
 206 The price field in purchase records is still C<sellprice>.
 
 210 C<source> and C<spec> are tainted. If you store data directly in C<spec>, sanitize.
 
 217 L<SL::PriceSource::Price>,
 
 218 L<SL::PriceSource::ALL>
 
 226 Sven Schoeling E<lt>s.schoeling@linet-services.deE<gt>