Einkauf/Verkauf: Bemerkungsfeld mit HTML-Editor ausgestattet
[kivitendo-erp.git] / SL / DB / Order.pm
index daab5dd..48e2be6 100644 (file)
@@ -9,13 +9,14 @@ use List::Util qw(max);
 
 use SL::DB::MetaSetup::Order;
 use SL::DB::Manager::Order;
 
 use SL::DB::MetaSetup::Order;
 use SL::DB::Manager::Order;
-use SL::DB::Invoice;
+use SL::DB::Helper::AttrHTML;
 use SL::DB::Helper::FlattenToForm;
 use SL::DB::Helper::LinkedRecords;
 use SL::DB::Helper::PriceTaxCalculator;
 use SL::DB::Helper::PriceUpdater;
 use SL::DB::Helper::TransNumberGenerator;
 use SL::RecordLinks;
 use SL::DB::Helper::FlattenToForm;
 use SL::DB::Helper::LinkedRecords;
 use SL::DB::Helper::PriceTaxCalculator;
 use SL::DB::Helper::PriceUpdater;
 use SL::DB::Helper::TransNumberGenerator;
 use SL::RecordLinks;
+use Rose::DB::Object::Helpers qw(as_tree);
 
 __PACKAGE__->meta->add_relationship(
   orderitems => {
 
 __PACKAGE__->meta->add_relationship(
   orderitems => {
@@ -31,23 +32,45 @@ __PACKAGE__->meta->add_relationship(
     class                  => 'SL::DB::PeriodicInvoicesConfig',
     column_map             => { id => 'oe_id' },
   },
     class                  => 'SL::DB::PeriodicInvoicesConfig',
     column_map             => { id => 'oe_id' },
   },
-  periodic_invoices        => {
-    type                   => 'one to many',
-    class                  => 'SL::DB::PeriodicInvoice',
-    column_map             => { id => 'oe_id' },
-  },
-  payment_term => {
-    type       => 'one to one',
-    class      => 'SL::DB::PaymentTerm',
-    column_map => { payment_id => 'id' },
+  custom_shipto            => {
+    type                   => 'one to one',
+    class                  => 'SL::DB::Shipto',
+    column_map             => { id => 'trans_id' },
+    query_args             => [ module => 'OE' ],
   },
 );
 
 __PACKAGE__->meta->initialize;
 
   },
 );
 
 __PACKAGE__->meta->initialize;
 
+__PACKAGE__->attr_html('notes');
+
+__PACKAGE__->before_save('_before_save_set_ord_quo_number');
+
+# hooks
+
+sub _before_save_set_ord_quo_number {
+  my ($self) = @_;
+
+  # ordnumber is 'NOT NULL'. Therefore make sure it's always set to at
+  # least an empty string, even if we're saving a quotation.
+  $self->ordnumber('') if !$self->ordnumber;
+
+  my $field = $self->quotation ? 'quonumber' : 'ordnumber';
+  $self->create_trans_number if !$self->$field;
+
+  return 1;
+}
+
 # methods
 
 sub items { goto &orderitems; }
 # methods
 
 sub items { goto &orderitems; }
+sub add_items { goto &add_orderitems; }
+
+sub items_sorted {
+  my ($self) = @_;
+
+  return [ sort {$a->position <=> $b->position } @{ $self->items } ];
+}
 
 sub type {
   my $self = shift;
 
 sub type {
   my $self = shift;
@@ -64,6 +87,23 @@ sub is_type {
   return shift->type eq shift;
 }
 
   return shift->type eq shift;
 }
 
+sub displayable_type {
+  my $type = shift->type;
+
+  return $::locale->text('Sales quotation')   if $type eq 'sales_quotation';
+  return $::locale->text('Request quotation') if $type eq 'request_quotation';
+  return $::locale->text('Sales Order')       if $type eq 'sales_order';
+  return $::locale->text('Purchase Order')    if $type eq 'purchase_order';
+
+  die 'invalid type';
+}
+
+
+sub is_sales {
+  croak 'not an accessor' if @_ > 1;
+  return !!shift->customer_id;
+}
+
 sub invoices {
   my $self   = shift;
   my %params = @_;
 sub invoices {
   my $self   = shift;
   my %params = @_;
@@ -71,6 +111,7 @@ sub invoices {
   if ($self->quotation) {
     return [];
   } else {
   if ($self->quotation) {
     return [];
   } else {
+    require SL::DB::Invoice;
     return SL::DB::Manager::Invoice->get_all(
       query => [
         ordnumber => $self->ordnumber,
     return SL::DB::Manager::Invoice->get_all(
       query => [
         ordnumber => $self->ordnumber,
@@ -80,6 +121,12 @@ sub invoices {
   }
 }
 
   }
 }
 
+sub displayable_state {
+  my ($self) = @_;
+
+  return $self->closed ? $::locale->text('closed') : $::locale->text('open');
+}
+
 sub abschlag_invoices {
   return shift()->invoices(query => [ abschlag => 1 ]);
 }
 sub abschlag_invoices {
   return shift()->invoices(query => [ abschlag => 1 ]);
 }
@@ -94,11 +141,12 @@ sub convert_to_invoice {
   croak("Conversion to invoices is only supported for sales records") unless $self->customer_id;
 
   my $invoice;
   croak("Conversion to invoices is only supported for sales records") unless $self->customer_id;
 
   my $invoice;
-  if (!$self->db->do_transaction(sub {
+  if (!$self->db->with_transaction(sub {
+    require SL::DB::Invoice;
     $invoice = SL::DB::Invoice->new_from($self)->post(%params) || die;
     $self->link_to_record($invoice);
     $self->update_attributes(closed => 1);
     $invoice = SL::DB::Invoice->new_from($self)->post(%params) || die;
     $self->link_to_record($invoice);
     $self->update_attributes(closed => 1);
-    # die;
+    1;
   })) {
     return undef;
   }
   })) {
     return undef;
   }
@@ -106,6 +154,46 @@ sub convert_to_invoice {
   return $invoice;
 }
 
   return $invoice;
 }
 
+sub convert_to_delivery_order {
+  my ($self, @args) = @_;
+
+  my ($delivery_order, $custom_shipto);
+  if (!$self->db->with_transaction(sub {
+    require SL::DB::DeliveryOrder;
+    ($delivery_order, $custom_shipto) = SL::DB::DeliveryOrder->new_from($self, @args);
+    $delivery_order->save;
+    $custom_shipto->save if $custom_shipto;
+    $self->link_to_record($delivery_order);
+    $self->update_attributes(delivered => 1);
+    1;
+  })) {
+    return wantarray ? () : undef;
+  }
+
+  return wantarray ? ($delivery_order, $custom_shipto) : $delivery_order;
+}
+
+sub number {
+  my $self = shift;
+
+  my %number_method = (
+    sales_order       => 'ordnumber',
+    sales_quotation   => 'quonumber',
+    purchase_order    => 'ordnumber',
+    request_quotation => 'quonumber',
+  );
+
+  return $self->${ \ $number_method{$self->type} }(@_);
+}
+
+sub customervendor {
+  $_[0]->is_sales ? $_[0]->customer : $_[0]->vendor;
+}
+
+sub date {
+  goto &transdate;
+}
+
 1;
 
 __END__
 1;
 
 __END__
@@ -116,13 +204,13 @@ SL::DB::Order - Order Datenbank Objekt.
 
 =head1 FUNCTIONS
 
 
 =head1 FUNCTIONS
 
-=head2 type
+=head2 C<type>
 
 Returns one of the following string types:
 
 =over 4
 
 
 Returns one of the following string types:
 
 =over 4
 
-=item saes_order
+=item sales_order
 
 =item purchase_order
 
 
 =item purchase_order
 
@@ -132,11 +220,33 @@ Returns one of the following string types:
 
 =back
 
 
 =back
 
-=head2 is_type TYPE
+=head2 C<is_type TYPE>
+
+Returns true if the order is of the given type.
+
+=head2 C<convert_to_delivery_order %params>
 
 
-Rreturns true if the order is of the given type.
+Creates a new delivery order with C<$self> as the basis by calling
+L<SL::DB::DeliveryOrder::new_from>. That delivery order is saved, and
+C<$self> is linked to the new invoice via
+L<SL::DB::RecordLink>. C<$self>'s C<delivered> attribute is set to
+C<true>, and C<$self> is saved.
 
 
-=item C<convert_to_invoice %params>
+The arguments in C<%params> are passed to
+L<SL::DB::DeliveryOrder::new_from>.
+
+Returns C<undef> on failure. Otherwise the return value depends on the
+context. In list context the new delivery order and a shipto instance
+will be returned. In scalar instance only the delivery order instance
+is returned.
+
+Custom shipto addresses (the ones specific to the sales/purchase
+record and not to the customer/vendor) are only linked from C<shipto>
+to C<delivery_orders>. Meaning C<delivery_orders.shipto_id> will not
+be filled in that case. That's why a separate shipto object is created
+and returned.
+
+=head2 C<convert_to_invoice %params>
 
 Creates a new invoice with C<$self> as the basis by calling
 L<SL::DB::Invoice::new_from>. That invoice is posted, and C<$self> is
 
 Creates a new invoice with C<$self> as the basis by calling
 L<SL::DB::Invoice::new_from>. That invoice is posted, and C<$self> is
@@ -151,7 +261,7 @@ nothing is created or changed in the database.
 
 At the moment only sales quotations and sales orders can be converted.
 
 
 At the moment only sales quotations and sales orders can be converted.
 
-=item C<create_sales_process>
+=head2 C<create_sales_process>
 
 Creates and saves a new sales process. Can only be called for sales
 orders.
 
 Creates and saves a new sales process. Can only be called for sales
 orders.
@@ -161,8 +271,6 @@ C<$self> and to all sales quotations that are linked to C<$self>.
 
 Returns the newly created process instance.
 
 
 Returns the newly created process instance.
 
-=back
-
 =head1 BUGS
 
 Nothing here yet.
 =head1 BUGS
 
 Nothing here yet.