Revision 6c053f87
Von Tamino Steinert vor mehr als 2 Jahren hinzugefügt
| SL/DB/Helper/ALL.pm | ||
|---|---|---|
| use SL::DB::ProjectStatus;
 | ||
| use SL::DB::ProjectType;
 | ||
| use SL::DB::PurchaseInvoice;
 | ||
| use SL::DB::Reclamation;
 | ||
| use SL::DB::ReclamationItem;
 | ||
| use SL::DB::ReclamationReason;
 | ||
| use SL::DB::ReconciliationLink;
 | ||
| use SL::DB::RecordLink;
 | ||
| use SL::DB::RecordTemplate;
 | ||
| SL/DB/Helper/Mappings.pm | ||
|---|---|---|
|   project_roles                  => 'project_role',
 | ||
|   project_statuses               => 'project_status',
 | ||
|   project_types                  => 'project_type',
 | ||
|   reclamations                   => 'Reclamation',
 | ||
|   reclamation_items              => 'ReclamationItem',
 | ||
|   reclamation_reasons            => 'ReclamationReason',
 | ||
|   reconciliation_links           => 'reconciliation_link',
 | ||
|   record_links                   => 'record_link',
 | ||
|   record_templates               => 'record_template',
 | ||
| SL/DB/Manager/Reclamation.pm | ||
|---|---|---|
| package SL::DB::Manager::Reclamation;
 | ||
|  | ||
| use strict;
 | ||
|  | ||
| use parent qw(SL::DB::Helper::Manager);
 | ||
|  | ||
| use SL::DB::Helper::Paginated;
 | ||
| use SL::DB::Helper::Sorted;
 | ||
| use SL::DB::Helper::Filtered;
 | ||
|  | ||
| sub object_class { 'SL::DB::Reclamation' }
 | ||
|  | ||
| __PACKAGE__->make_manager_methods;
 | ||
|  | ||
| __PACKAGE__->add_filter_specs(
 | ||
|   type => sub {
 | ||
|     my ($key, $value, $prefix) = @_;
 | ||
|     return __PACKAGE__->type_filter($value, $prefix);
 | ||
|   },
 | ||
|   # todo when is this used?
 | ||
|   #all => sub {
 | ||
|   #  my ($key, $value, $prefix) = @_;
 | ||
|   #  return or => [ map { $prefix . $_ => $value } qw(record_number customer.name vendor.name transaction_description) ]
 | ||
|   #}
 | ||
| );
 | ||
|  | ||
| sub type_filter {
 | ||
|   my $class  = shift;
 | ||
|   my $type   = lc(shift || '');
 | ||
|   my $prefix = shift || '';
 | ||
|  | ||
|   return (and => [ "!customer_id" => undef ]) if $type eq 'sales_reclamation';
 | ||
|   return (and => [ "!vendor_id"   => undef ]) if $type eq 'purchase_reclamation';
 | ||
|  | ||
|   die "Unknown type $type";
 | ||
| }
 | ||
|  | ||
| sub _sort_spec {
 | ||
|   return (
 | ||
|     default                   => [ 'transdate', 1 ],
 | ||
|     nulls                     => {
 | ||
|       transaction_description => 'FIRST',
 | ||
|       default                 => 'LAST',
 | ||
|     },
 | ||
|     columns                   => {
 | ||
|       SIMPLE                  => 'ALL',
 | ||
|       customer                => 'lower(customer.name)',
 | ||
|       vendor                  => 'lower(vendor.name)',
 | ||
|       employee                => 'lower(employee.name)',
 | ||
|       globalprojectnumber     => 'lower(globalproject.projectnumber)',
 | ||
|  | ||
|       # Bug in Rose::DB::Object: the next should be
 | ||
|       # "globalproject.project_type.description". This workaround will
 | ||
|       # only work if no other table with "project_type" is visible in
 | ||
|       # the current query
 | ||
|       globalproject_type      => 'lower(project_type.description)',
 | ||
|  | ||
|       map { ( $_ => "lower(reclamations.$_)" ) }
 | ||
|         qw(record_number cv_record_number shippingpoint shipvia notes intnotes
 | ||
|            transaction_description
 | ||
|         ),
 | ||
|     });
 | ||
| }
 | ||
|  | ||
| 1;
 | ||
| SL/DB/Manager/ReclamationItem.pm | ||
|---|---|---|
| # This file has been auto-generated only because it didn't exist.
 | ||
| # Feel free to modify it at will; it will not be overwritten automatically.
 | ||
|  | ||
| package SL::DB::Manager::ReclamationItem;
 | ||
|  | ||
| use strict;
 | ||
|  | ||
| use parent qw(SL::DB::Helper::Manager);
 | ||
|  | ||
| sub object_class { 'SL::DB::ReclamationItem' }
 | ||
|  | ||
| __PACKAGE__->make_manager_methods;
 | ||
|  | ||
| 1;
 | ||
| SL/DB/Manager/ReclamationReason.pm | ||
|---|---|---|
| package SL::DB::Manager::ReclamationReason;
 | ||
|  | ||
| use strict;
 | ||
|  | ||
| use parent qw(SL::DB::Helper::Manager);
 | ||
| use SL::DB::Helper::Paginated;
 | ||
| use SL::DB::Helper::Filtered;
 | ||
|  | ||
| use SL::DB::Helper::Sorted;
 | ||
|  | ||
| sub object_class { 'SL::DB::ReclamationReason' }
 | ||
|  | ||
| __PACKAGE__->make_manager_methods;
 | ||
| __PACKAGE__->add_filter_specs(
 | ||
|   all => sub {
 | ||
|     my ($key, $value, $prefix) = @_;
 | ||
|     return or => [ map { $prefix . $_ => $value } qw(reclamation_reason) ]
 | ||
|   },
 | ||
| );
 | ||
|  | ||
| sub _sort_spec {
 | ||
|   return ( default => [ 'position', 1 ],
 | ||
|            columns => { SIMPLE => 'ALL' });
 | ||
| }
 | ||
| 1;
 | ||
| SL/DB/MetaSetup/Reclamation.pm | ||
|---|---|---|
| # This file has been auto-generated. Do not modify it; it will be overwritten
 | ||
| # by rose_auto_create_model.pl automatically.
 | ||
| package SL::DB::Reclamation;
 | ||
|  | ||
| use strict;
 | ||
|  | ||
| use parent qw(SL::DB::Object);
 | ||
|  | ||
| __PACKAGE__->meta->table('reclamations');
 | ||
|  | ||
| __PACKAGE__->meta->columns(
 | ||
|   amount                  => { type => 'numeric', precision => 15, scale => 5 },
 | ||
|   closed                  => { type => 'boolean', default => 'false', not_null => 1 },
 | ||
|   contact_id              => { type => 'integer' },
 | ||
|   currency_id             => { type => 'integer', not_null => 1 },
 | ||
|   customer_id             => { type => 'integer' },
 | ||
|   cv_record_number        => { type => 'text' },
 | ||
|   delivered               => { type => 'boolean', default => 'false', not_null => 1 },
 | ||
|   delivery_term_id        => { type => 'integer' },
 | ||
|   department_id           => { type => 'integer' },
 | ||
|   employee_id             => { type => 'integer', not_null => 1 },
 | ||
|   exchangerate            => { type => 'numeric', precision => 15, scale => 5 },
 | ||
|   globalproject_id        => { type => 'integer' },
 | ||
|   id                      => { type => 'integer', not_null => 1, sequence => 'id' },
 | ||
|   intnotes                => { type => 'text' },
 | ||
|   itime                   => { type => 'timestamp', default => 'now()' },
 | ||
|   language_id             => { type => 'integer' },
 | ||
|   mtime                   => { type => 'timestamp' },
 | ||
|   netamount               => { type => 'numeric', precision => 15, scale => 5 },
 | ||
|   notes                   => { type => 'text' },
 | ||
|   payment_id              => { type => 'integer' },
 | ||
|   record_number           => { type => 'text', not_null => 1 },
 | ||
|   reqdate                 => { type => 'date' },
 | ||
|   salesman_id             => { type => 'integer' },
 | ||
|   shippingpoint           => { type => 'text' },
 | ||
|   shipto_id               => { type => 'integer' },
 | ||
|   shipvia                 => { type => 'text' },
 | ||
|   tax_point               => { type => 'date' },
 | ||
|   taxincluded             => { type => 'boolean', not_null => 1 },
 | ||
|   taxzone_id              => { type => 'integer', not_null => 1 },
 | ||
|   transaction_description => { type => 'text' },
 | ||
|   transdate               => { type => 'date', default => 'now()' },
 | ||
|   vendor_id               => { type => 'integer' },
 | ||
| );
 | ||
|  | ||
| __PACKAGE__->meta->primary_key_columns([ 'id' ]);
 | ||
|  | ||
| __PACKAGE__->meta->allow_inline_column_values(1);
 | ||
|  | ||
| __PACKAGE__->meta->foreign_keys(
 | ||
|   contact => {
 | ||
|     class       => 'SL::DB::Contact',
 | ||
|     key_columns => { contact_id => 'cp_id' },
 | ||
|   },
 | ||
|  | ||
|   currency => {
 | ||
|     class       => 'SL::DB::Currency',
 | ||
|     key_columns => { currency_id => 'id' },
 | ||
|   },
 | ||
|  | ||
|   customer => {
 | ||
|     class       => 'SL::DB::Customer',
 | ||
|     key_columns => { customer_id => 'id' },
 | ||
|   },
 | ||
|  | ||
|   delivery_term => {
 | ||
|     class       => 'SL::DB::DeliveryTerm',
 | ||
|     key_columns => { delivery_term_id => 'id' },
 | ||
|   },
 | ||
|  | ||
|   department => {
 | ||
|     class       => 'SL::DB::Department',
 | ||
|     key_columns => { department_id => 'id' },
 | ||
|   },
 | ||
|  | ||
|   employee => {
 | ||
|     class       => 'SL::DB::Employee',
 | ||
|     key_columns => { employee_id => 'id' },
 | ||
|   },
 | ||
|  | ||
|   globalproject => {
 | ||
|     class       => 'SL::DB::Project',
 | ||
|     key_columns => { globalproject_id => 'id' },
 | ||
|   },
 | ||
|  | ||
|   language => {
 | ||
|     class       => 'SL::DB::Language',
 | ||
|     key_columns => { language_id => 'id' },
 | ||
|   },
 | ||
|  | ||
|   payment => {
 | ||
|     class       => 'SL::DB::PaymentTerm',
 | ||
|     key_columns => { payment_id => 'id' },
 | ||
|   },
 | ||
|  | ||
|   salesman => {
 | ||
|     class       => 'SL::DB::Employee',
 | ||
|     key_columns => { salesman_id => 'id' },
 | ||
|   },
 | ||
|  | ||
|   shipto => {
 | ||
|     class       => 'SL::DB::Shipto',
 | ||
|     key_columns => { shipto_id => 'shipto_id' },
 | ||
|   },
 | ||
|  | ||
|   taxzone => {
 | ||
|     class       => 'SL::DB::TaxZone',
 | ||
|     key_columns => { taxzone_id => 'id' },
 | ||
|   },
 | ||
|  | ||
|   vendor => {
 | ||
|     class       => 'SL::DB::Vendor',
 | ||
|     key_columns => { vendor_id => 'id' },
 | ||
|   },
 | ||
| );
 | ||
|  | ||
| 1;
 | ||
| ;
 | ||
| SL/DB/MetaSetup/ReclamationItem.pm | ||
|---|---|---|
| # This file has been auto-generated. Do not modify it; it will be overwritten
 | ||
| # by rose_auto_create_model.pl automatically.
 | ||
| package SL::DB::ReclamationItem;
 | ||
|  | ||
| use strict;
 | ||
|  | ||
| use parent qw(SL::DB::Object);
 | ||
|  | ||
| __PACKAGE__->meta->table('reclamation_items');
 | ||
|  | ||
| __PACKAGE__->meta->columns(
 | ||
|   active_discount_source => { type => 'text', default => '', not_null => 1 },
 | ||
|   active_price_source    => { type => 'text', default => '', not_null => 1 },
 | ||
|   base_qty               => { type => 'float', precision => 4, scale => 4 },
 | ||
|   description            => { type => 'text' },
 | ||
|   discount               => { type => 'float', precision => 4, scale => 4 },
 | ||
|   id                     => { type => 'serial', not_null => 1 },
 | ||
|   itime                  => { type => 'timestamp', default => 'now()' },
 | ||
|   lastcost               => { type => 'numeric', precision => 15, scale => 5 },
 | ||
|   longdescription        => { type => 'text' },
 | ||
|   mtime                  => { type => 'timestamp' },
 | ||
|   parts_id               => { type => 'integer', not_null => 1 },
 | ||
|   position               => { type => 'integer', not_null => 1 },
 | ||
|   price_factor           => { type => 'numeric', default => 1, precision => 15, scale => 5 },
 | ||
|   price_factor_id        => { type => 'integer' },
 | ||
|   pricegroup_id          => { type => 'integer' },
 | ||
|   project_id             => { type => 'integer' },
 | ||
|   qty                    => { type => 'float', precision => 4, scale => 4 },
 | ||
|   reason_description_ext => { type => 'text' },
 | ||
|   reason_description_int => { type => 'text' },
 | ||
|   reason_id              => { type => 'integer', not_null => 1 },
 | ||
|   reclamation_id         => { type => 'integer', not_null => 1 },
 | ||
|   reqdate                => { type => 'date' },
 | ||
|   sellprice              => { type => 'numeric', precision => 15, scale => 5 },
 | ||
|   serialnumber           => { type => 'text' },
 | ||
|   unit                   => { type => 'varchar', length => 20 },
 | ||
| );
 | ||
|  | ||
| __PACKAGE__->meta->primary_key_columns([ 'id' ]);
 | ||
|  | ||
| __PACKAGE__->meta->allow_inline_column_values(1);
 | ||
|  | ||
| __PACKAGE__->meta->foreign_keys(
 | ||
|   part => {
 | ||
|     class       => 'SL::DB::Part',
 | ||
|     key_columns => { parts_id => 'id' },
 | ||
|   },
 | ||
|  | ||
|   price_factor_obj => {
 | ||
|     class       => 'SL::DB::PriceFactor',
 | ||
|     key_columns => { price_factor_id => 'id' },
 | ||
|   },
 | ||
|  | ||
|   pricegroup => {
 | ||
|     class       => 'SL::DB::Pricegroup',
 | ||
|     key_columns => { pricegroup_id => 'id' },
 | ||
|   },
 | ||
|  | ||
|   project => {
 | ||
|     class       => 'SL::DB::Project',
 | ||
|     key_columns => { project_id => 'id' },
 | ||
|   },
 | ||
|  | ||
|   reason => {
 | ||
|     class       => 'SL::DB::ReclamationReason',
 | ||
|     key_columns => { reason_id => 'id' },
 | ||
|   },
 | ||
|  | ||
|   reclamation => {
 | ||
|     class       => 'SL::DB::Reclamation',
 | ||
|     key_columns => { reclamation_id => 'id' },
 | ||
|   },
 | ||
|  | ||
|   unit_obj => {
 | ||
|     class       => 'SL::DB::Unit',
 | ||
|     key_columns => { unit => 'name' },
 | ||
|   },
 | ||
| );
 | ||
|  | ||
| 1;
 | ||
| ;
 | ||
| SL/DB/MetaSetup/ReclamationReason.pm | ||
|---|---|---|
| # This file has been auto-generated. Do not modify it; it will be overwritten
 | ||
| # by rose_auto_create_model.pl automatically.
 | ||
| package SL::DB::ReclamationReason;
 | ||
|  | ||
| use strict;
 | ||
|  | ||
| use parent qw(SL::DB::Object);
 | ||
|  | ||
| __PACKAGE__->meta->table('reclamation_reasons');
 | ||
|  | ||
| __PACKAGE__->meta->columns(
 | ||
|   description        => { type => 'text', not_null => 1 },
 | ||
|   id                 => { type => 'serial', not_null => 1 },
 | ||
|   itime              => { type => 'timestamp', default => 'now()' },
 | ||
|   mtime              => { type => 'timestamp' },
 | ||
|   name               => { type => 'text', not_null => 1 },
 | ||
|   position           => { type => 'integer', not_null => 1 },
 | ||
|   valid_for_purchase => { type => 'boolean', default => 'false', not_null => 1 },
 | ||
|   valid_for_sales    => { type => 'boolean', default => 'false', not_null => 1 },
 | ||
| );
 | ||
|  | ||
| __PACKAGE__->meta->primary_key_columns([ 'id' ]);
 | ||
|  | ||
| __PACKAGE__->meta->allow_inline_column_values(1);
 | ||
|  | ||
| 1;
 | ||
| ;
 | ||
| SL/DB/Reclamation.pm | ||
|---|---|---|
| package SL::DB::Reclamation;
 | ||
|  | ||
| use utf8;
 | ||
| use strict;
 | ||
|  | ||
| use Carp;
 | ||
| use DateTime;
 | ||
| use List::Util qw(max sum0);
 | ||
| use List::MoreUtils qw(any);
 | ||
|  | ||
| use SL::DB::MetaSetup::Reclamation;
 | ||
| use SL::DB::Manager::Reclamation;
 | ||
| use SL::DB::Helper::Attr;
 | ||
| use SL::DB::Helper::AttrHTML;
 | ||
| use SL::DB::Helper::AttrSorted;
 | ||
| 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::Locale::String qw(t8);
 | ||
| use SL::RecordLinks;
 | ||
| use Rose::DB::Object::Helpers qw(as_tree);
 | ||
|  | ||
| __PACKAGE__->meta->add_relationship(
 | ||
|  | ||
|   reclamation_items => {
 | ||
|     type         => 'one to many',
 | ||
|     class        => 'SL::DB::ReclamationItem',
 | ||
|     column_map   => { id => 'reclamation_id' },
 | ||
|     manager_args => {
 | ||
|       with_objects => [ 'part', 'reason' ]
 | ||
|     }
 | ||
|   },
 | ||
|   custom_shipto            => {
 | ||
|     type                   => 'one to one',
 | ||
|     class                  => 'SL::DB::Shipto',
 | ||
|     column_map             => { id => 'trans_id' },
 | ||
|     query_args             => [ module => 'Reclamation' ],
 | ||
|   },
 | ||
|   exchangerate_obj         => {
 | ||
|     type                   => 'one to one',
 | ||
|     class                  => 'SL::DB::Exchangerate',
 | ||
|     column_map             => { currency_id => 'currency_id', transdate => 'transdate' },
 | ||
|   },
 | ||
| );
 | ||
|  | ||
| SL::DB::Helper::Attr::make(__PACKAGE__, daily_exchangerate => 'numeric');
 | ||
|  | ||
| __PACKAGE__->meta->initialize;
 | ||
|  | ||
| __PACKAGE__->attr_html('notes');
 | ||
| __PACKAGE__->attr_sorted('items');
 | ||
|  | ||
| __PACKAGE__->before_save('_before_save_set_record_number');
 | ||
| __PACKAGE__->before_save('_before_save_remove_empty_custom_shipto');
 | ||
| __PACKAGE__->before_save('_before_save_set_custom_shipto_module');
 | ||
|  | ||
| # hooks
 | ||
|  | ||
| sub _before_save_set_record_number {
 | ||
|   my ($self) = @_;
 | ||
|  | ||
|   $self->create_trans_number if !$self->record_number;
 | ||
|  | ||
|   return 1;
 | ||
| }
 | ||
|  | ||
| sub _before_save_remove_empty_custom_shipto {
 | ||
|   my ($self) = @_;
 | ||
|  | ||
|   $self->custom_shipto(undef) if $self->custom_shipto && $self->custom_shipto->is_empty;
 | ||
|  | ||
|   return 1;
 | ||
| }
 | ||
|  | ||
| sub _before_save_set_custom_shipto_module {
 | ||
|   my ($self) = @_;
 | ||
|  | ||
|   $self->custom_shipto->module('Reclamation') if $self->custom_shipto;
 | ||
|  | ||
|   return 1;
 | ||
| }
 | ||
|  | ||
| # methods
 | ||
|  | ||
| sub items { goto &reclamation_items; }
 | ||
| sub add_items { goto &add_reclamation_items; }
 | ||
| sub record_items { goto &reclamation_items; }
 | ||
|  | ||
| sub type {
 | ||
|   my ($self) = @_;
 | ||
|  | ||
|   return 'sales_reclamation'    if $self->customer_id;
 | ||
|   return 'purchase_reclamation' if $self->vendor_id;
 | ||
|  | ||
|   return;
 | ||
| }
 | ||
|  | ||
| sub is_type {
 | ||
|   my ($self, $type) = @_;
 | ||
|   return $self->type eq $type;
 | ||
| }
 | ||
|  | ||
| sub effective_tax_point {
 | ||
|   my ($self) = @_;
 | ||
|  | ||
|   return $self->tax_point || $self->reqdate || $self->transdate;
 | ||
| }
 | ||
|  | ||
| sub displayable_type {
 | ||
|   my $type = shift->type;
 | ||
|  | ||
|   return $::locale->text('Sales Reclamation')    if $type eq 'sales_reclamation';
 | ||
|   return $::locale->text('Purchase Reclamation') if $type eq 'purchase_reclamation';
 | ||
|  | ||
|   die 'invalid type';
 | ||
| }
 | ||
|  | ||
| sub displayable_name {
 | ||
|   join ' ', grep $_, map $_[0]->$_, qw(displayable_type record_number);
 | ||
| };
 | ||
|  | ||
| sub is_sales {
 | ||
|   croak 'not an accessor' if @_ > 1;
 | ||
|   return !!shift->customer_id;
 | ||
| }
 | ||
|  | ||
| sub daily_exchangerate {
 | ||
|   my ($self, $val) = @_;
 | ||
|  | ||
|   return 1 if $self->currency_id == $::instance_conf->get_currency_id;
 | ||
|  | ||
|   my $rate = (any { $self->is_type($_) } qw(sales_reclamation))    ? 'buy'
 | ||
|            : (any { $self->is_type($_) } qw(purchase_reclamation)) ? 'sell'
 | ||
|            : undef;
 | ||
|   return if !$rate;
 | ||
|  | ||
|   if (defined $val) {
 | ||
|     croak t8('exchange rate has to be positive') if $val <= 0;
 | ||
|     if (!$self->exchangerate_obj) {
 | ||
|       $self->exchangerate_obj(SL::DB::Exchangerate->new(
 | ||
|         currency_id => $self->currency_id,
 | ||
|         transdate   => $self->transdate,
 | ||
|         $rate       => $val,
 | ||
|       ));
 | ||
|     } elsif (!defined $self->exchangerate_obj->$rate) {
 | ||
|       $self->exchangerate_obj->$rate($val);
 | ||
|     } else {
 | ||
|       croak t8('exchange rate already exists, no update allowed');
 | ||
|     }
 | ||
|   }
 | ||
|   return $self->exchangerate_obj->$rate if $self->exchangerate_obj;
 | ||
| }
 | ||
|  | ||
| sub taxes {
 | ||
|   my ($self) = @_;
 | ||
|   # add taxes to recalmation
 | ||
|   my %pat = $self->calculate_prices_and_taxes();
 | ||
|   my @taxes;
 | ||
|   foreach my $tax_id (keys %{ $pat{taxes_by_tax_id} }) {
 | ||
|     my $netamount = sum0 map { $pat{amounts}->{$_}->{amount} } grep { $pat{amounts}->{$_}->{tax_id} == $tax_id } keys %{ $pat{amounts} };
 | ||
|     push(@taxes, { amount    => $pat{taxes_by_tax_id}->{$tax_id},
 | ||
|                                 netamount => $netamount,
 | ||
|                                 tax       => SL::DB::Tax->new(id => $tax_id)->load });
 | ||
|   }
 | ||
|   return \@taxes;
 | ||
| }
 | ||
|  | ||
| sub displayable_state {
 | ||
|   my ($self) = @_;
 | ||
|  | ||
|   return $self->closed ? $::locale->text('closed') : $::locale->text('open');
 | ||
| }
 | ||
|  | ||
| sub valid_reclamation_reasons {
 | ||
|   my ($self) = @_;
 | ||
|  | ||
|   my $valid_for_type = ($self->type =~ m{sales} ? 'valid_for_sales' : 'valid_for_purchase');
 | ||
|   return SL::DB::Manager::ReclamationReason->get_all_sorted(
 | ||
|       where => [  $valid_for_type => 1 ]);
 | ||
| }
 | ||
|  | ||
| #TODO(Werner): überprüfen ob alle Felder richtig gestetzt werden
 | ||
| sub new_from {
 | ||
|   my ($class, $source, %params) = @_;
 | ||
|   my %allowed_sources = map { $_ => 1 } qw(
 | ||
|     SL::DB::Reclamation
 | ||
|   );
 | ||
|   unless( $allowed_sources{ref $source} ) {
 | ||
|     croak("Unsupported source object type '" . ref($source) . "'");
 | ||
|   }
 | ||
|   croak("A destination type must be given as parameter") unless $params{destination_type};
 | ||
|  | ||
|   my $destination_type  = delete $params{destination_type};
 | ||
|  | ||
|   my @from_tos = (
 | ||
|     #Reclamation
 | ||
|     { from => 'sales_reclamation',       to => 'sales_reclamation',    abbr => 'srsr', },
 | ||
|     { from => 'purchase_reclamation',    to => 'purchase_reclamation', abbr => 'prpr', },
 | ||
|     { from => 'sales_reclamation',       to => 'purchase_reclamation', abbr => 'srpr', },
 | ||
|     { from => 'purchase_reclamation',    to => 'sales_reclamation',    abbr => 'prsr', },
 | ||
|   );
 | ||
|   my $from_to = (grep { $_->{from} eq $source->type && $_->{to} eq $destination_type} @from_tos)[0];
 | ||
|   if (!$from_to) {
 | ||
|     croak("Cannot convert from '" . $source->type . "' to '" . $destination_type . "'");
 | ||
|   }
 | ||
|  | ||
|   my $is_abbr_any = sub {
 | ||
|     any { $from_to->{abbr} eq $_ } @_;
 | ||
|   };
 | ||
|  | ||
|   my %record_args = (
 | ||
|     record_number => undef,
 | ||
|     employee => SL::DB::Manager::Employee->current,
 | ||
|     closed    => 0,
 | ||
|     delivered => 0,
 | ||
|     transdate => DateTime->today_local,
 | ||
|     reqdate => DateTime->today_local->next_workday(),
 | ||
|   );
 | ||
|   if ( $is_abbr_any->(qw(srsr prpr srpr prsr)) ) { #Reclamation
 | ||
|     map { $record_args{$_} = $source->$_ } # {{{ for vim folds
 | ||
|     qw(
 | ||
|       amount
 | ||
|       contact_id
 | ||
|       currency_id
 | ||
|       customer_id
 | ||
|       cv_record_number
 | ||
|       delivery_term_id
 | ||
|       department_id
 | ||
|       exchangerate
 | ||
|       globalproject_id
 | ||
|       intnotes
 | ||
|       language_id
 | ||
|       netamount
 | ||
|       notes
 | ||
|       payment_id
 | ||
|       salesman_id
 | ||
|       shippingpoint
 | ||
|       shipvia
 | ||
|       tax_point
 | ||
|       taxincluded
 | ||
|       taxzone_id
 | ||
|       transaction_description
 | ||
|       vendor_id
 | ||
|     ); # }}} for vim folds
 | ||
|   }
 | ||
|  | ||
|   if ( ($from_to->{from} =~ m{sales}) && ($from_to->{to} =~ m{purchase}) ) {
 | ||
|     $record_args{customer_id}      = undef;
 | ||
|     $record_args{salesman_id}      = undef;
 | ||
|     $record_args{payment_id}       = undef;
 | ||
|     $record_args{delivery_term_id} = undef;
 | ||
|   }
 | ||
|   if ( ($from_to->{from} =~ m{purchase}) && ($from_to->{to} =~ m{sales}) ) {
 | ||
|     $record_args{vendor_id} = undef;
 | ||
|     $record_args{salesman_id} = undef;
 | ||
|     $record_args{payment_id} = undef;
 | ||
|   }
 | ||
|  | ||
|  | ||
|   if ($source->can('shipto_id')) {
 | ||
|     # Custom shipto addresses (the ones specific to the sales/purchase record and
 | ||
|     # not to the customer/vendor) are only linked from shipto → record.
 | ||
|     # Meaning record.shipto_id will not be filled in that case.
 | ||
|     if (!$source->shipto_id && $source->id) {
 | ||
|       $record_args{custom_shipto} = $source->custom_shipto->clone($class) if $source->can('custom_shipto') && $source->custom_shipto;
 | ||
|     } elsif ($source->shipto_id) {
 | ||
|       $record_args{shipto_id} = $source->shipto_id;
 | ||
|     }
 | ||
|   }
 | ||
|  | ||
|   my $reclamation = $class->new(%record_args);
 | ||
|   $reclamation->assign_attributes(%{ $params{attributes} }) if $params{attributes};
 | ||
|  | ||
|   unless ($params{no_linked_records}) {
 | ||
|     $reclamation->{"converted_from_record_type_ref"} = ref($source);
 | ||
|     $reclamation->{"converted_from_record_id"} = $source->id;
 | ||
|   };
 | ||
|  | ||
|   my $items = delete($params{items}) || $source->items;
 | ||
|  | ||
|   my @items = map { SL::DB::ReclamationItem->new_from($_, $from_to->{to}, no_linked_records => $params{no_linked_records}); } @{ $items };
 | ||
|  | ||
|   @items = grep { $params{item_filter}->($_) } @items if $params{item_filter};
 | ||
|   @items = grep { $_->qty * 1 } @items if $params{skip_items_zero_qty};
 | ||
|   @items = grep { $_->qty >=0 } @items if $params{skip_items_negative_qty};
 | ||
|  | ||
|   $reclamation->items(\@items);
 | ||
|   return $reclamation;
 | ||
| }
 | ||
|  | ||
| sub customervendor {
 | ||
|   my ($reclamation) = @_;
 | ||
|   return $reclamation->is_sales ? $reclamation->customer : $reclamation->vendor;
 | ||
| }
 | ||
|  | ||
| sub date {
 | ||
|   goto &transdate;
 | ||
| }
 | ||
|  | ||
| sub digest {
 | ||
|   my ($self) = @_;
 | ||
|  | ||
|   sprintf "%s %s %s (%s)",
 | ||
|     $self->record_number,
 | ||
|     $self->customervendor->name,
 | ||
|     $self->amount_as_number,
 | ||
|     $self->date->to_kivitendo;
 | ||
| }
 | ||
|  | ||
| 1;
 | ||
|  | ||
| __END__
 | ||
|  | ||
| =pod
 | ||
|  | ||
| =encoding utf8
 | ||
|  | ||
| =head1 NAME
 | ||
|  | ||
| SL::DB::Reclamation - reclamation Datenbank Objekt.
 | ||
|  | ||
| =head1 FUNCTIONS
 | ||
|  | ||
| =head2 C<type>
 | ||
|  | ||
| Returns one of the following string types:
 | ||
|  | ||
| =over 4
 | ||
|  | ||
| =item sales_reclamation
 | ||
|  | ||
| =item purchase_reclamation
 | ||
|  | ||
| =item sales_quotation
 | ||
|  | ||
| =item request_quotation
 | ||
|  | ||
| =back
 | ||
|  | ||
| =head2 C<is_type TYPE>
 | ||
|  | ||
| Returns true if the reclamation is of the given type.
 | ||
|  | ||
| =head2 C<daily_exchangerate $val>
 | ||
|  | ||
| Gets or sets the exchangerate object's value. This is the value from the
 | ||
| table C<exchangerate> depending on the reclamation's currency, the transdate and
 | ||
| if it is a sales or purchase reclamation.
 | ||
|  | ||
| The reclamation object (respectively the table C<oe>) has an own column
 | ||
| C<exchangerate> which can be get or set with the accessor C<exchangerate>.
 | ||
|  | ||
| The idea is to drop the legacy table C<exchangerate> in the future and to
 | ||
| give all relevant tables it's own C<exchangerate> column.
 | ||
|  | ||
| So, this method is here if you need to access the "legacy" exchangerate via
 | ||
| an reclamation object.
 | ||
|  | ||
| =over 4
 | ||
|  | ||
| =item C<$val>
 | ||
|  | ||
| (optional) If given, the exchangerate in the "legacy" table is set to this
 | ||
| value, depending on currency, transdate and sales or purchase.
 | ||
|  | ||
| =back
 | ||
|  | ||
| =head2 C<convert_to_delivery_order %params>
 | ||
|  | ||
| Creates a new delivery reclamation with C<$self> as the basis by calling
 | ||
| L<SL::DB::DeliveryReclamation::new_from>. That delivery reclamation 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.
 | ||
|  | ||
| The arguments in C<%params> are passed to
 | ||
| L<SL::DB::DeliveryReclamation::new_from>.
 | ||
|  | ||
| Returns C<undef> on failure. Otherwise the new delivery reclamation will be
 | ||
| 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
 | ||
| linked to the new invoice via L<SL::DB::RecordLink>. C<$self>'s
 | ||
| C<closed> attribute is set to C<true>, and C<$self> is saved.
 | ||
|  | ||
| The arguments in C<%params> are passed to L<SL::DB::Invoice::post>.
 | ||
|  | ||
| Returns the new invoice instance on success and C<undef> on
 | ||
| failure. The whole process is run inside a transaction. On failure
 | ||
| nothing is created or changed in the database.
 | ||
|  | ||
| At the moment only sales quotations and sales reclamations can be converted.
 | ||
|  | ||
| =head2 C<new_from $source, %params>
 | ||
|  | ||
| Creates a new C<SL::DB::Reclamation> instance and copies as much
 | ||
| information from C<$source> as possible. At the moment only records with the
 | ||
| same destination type as the source type and sales reclamations from
 | ||
| sales quotations and purchase reclamations from requests for quotations can be
 | ||
| created.
 | ||
|  | ||
| The C<transdate> field will be set to the current date.
 | ||
|  | ||
| The conversion copies the reclamation items as well.
 | ||
|  | ||
| Returns the new reclamation instance. The object returned is not
 | ||
| saved.
 | ||
|  | ||
| C<%params> can include the following options
 | ||
| (C<destination_type> is mandatory):
 | ||
|  | ||
| =over 4
 | ||
|  | ||
| =item C<destination_type>
 | ||
|  | ||
| (mandatory)
 | ||
| The type of the newly created object. Can be C<sales_quotation>,
 | ||
| C<sales_reclamation>, C<purchase_quotation> or C<purchase_reclamation> for now.
 | ||
|  | ||
| =item C<items>
 | ||
|  | ||
| An optional array reference of RDBO instances for the items to use. If
 | ||
| missing then the method C<items_sorted> will be called on
 | ||
| C<$source>. This option can be used to override the sorting, to
 | ||
| exclude certain positions or to add additional ones.
 | ||
|  | ||
| =item C<skip_items_negative_qty>
 | ||
|  | ||
| If trueish then items with a negative quantity are skipped. Items with
 | ||
| a quantity of 0 are not affected by this option.
 | ||
|  | ||
| =item C<skip_items_zero_qty>
 | ||
|  | ||
| If trueish then items with a quantity of 0 are skipped.
 | ||
|  | ||
| =item C<item_filter>
 | ||
|  | ||
| An optional code reference that is called for each item with the item
 | ||
| as its sole parameter. Items for which the code reference returns a
 | ||
| falsish value will be skipped.
 | ||
|  | ||
| =item C<attributes>
 | ||
|  | ||
| An optional hash reference. If it exists then it is passed to C<new>
 | ||
| allowing the caller to set certain attributes for the new delivery
 | ||
| reclamation.
 | ||
|  | ||
| =back
 | ||
|  | ||
| =head1 BUGS
 | ||
|  | ||
| Nothing here yet.
 | ||
|  | ||
| =head1 AUTHOR
 | ||
|  | ||
| Sven Schöling <s.schoeling@linet-services.de>
 | ||
|  | ||
| =cut
 | ||
| SL/DB/ReclamationItem.pm | ||
|---|---|---|
| package SL::DB::ReclamationItem;
 | ||
|  | ||
| use utf8;
 | ||
| use strict;
 | ||
|  | ||
| use List::MoreUtils qw(any);
 | ||
|  | ||
| use SL::DB::MetaSetup::ReclamationItem;
 | ||
| use SL::DB::Manager::ReclamationItem;
 | ||
| use SL::DB::ReclamationReason;
 | ||
| use SL::DB::Helper::ActsAsList;
 | ||
| use SL::DB::Helper::LinkedRecords;
 | ||
| use SL::DB::Helper::RecordItem;
 | ||
| use SL::DB::Helper::CustomVariables (
 | ||
|   sub_module  => 'reclamation_items',
 | ||
|   cvars_alias => 1,
 | ||
|   overloads   => {
 | ||
|     parts_id => {
 | ||
|       class => 'SL::DB::Part',
 | ||
|       module => 'IC',
 | ||
|     }
 | ||
|   },
 | ||
| );
 | ||
| use SL::Helper::ShippedQty;
 | ||
|  | ||
| __PACKAGE__->meta->initialize;
 | ||
|  | ||
| __PACKAGE__->configure_acts_as_list(group_by => [qw(reclamation_id)]);
 | ||
|  | ||
| sub shipped_qty {
 | ||
|   my ($self, %params) = @_;
 | ||
|  | ||
|   my $force = delete $params{force};
 | ||
|  | ||
|   SL::Helper::ShippedQty->new(%params)->calculate($self)->write_to_objects if $force || !defined $self->{shipped_qty};
 | ||
|  | ||
|   $self->{shipped_qty};
 | ||
| }
 | ||
|  | ||
| sub is_linked_to_record {
 | ||
|   my ($self) = @_;
 | ||
|  | ||
|   if(scalar(@{$self->linked_records}) || $self->{converted_from_record_item_type_ref}) {
 | ||
|     return 1;
 | ||
|   }
 | ||
|  | ||
|   return 0;
 | ||
| }
 | ||
|  | ||
| #TODO(Werner): überprüfen ob alle Felder richtig gestetzt werden
 | ||
| sub new_from {
 | ||
|   my ($class, $source, $parent_type, %params) = @_;
 | ||
|   unless (any {ref($source) eq $_}
 | ||
|     qw(
 | ||
|       SL::DB::ReclamationItem
 | ||
|     )
 | ||
|   ) {
 | ||
|     croak("Unsupported source object type '" . ref($source) . "'");
 | ||
|   }
 | ||
|   my @custom_variables = map { _clone_cvar_for_reclamation_item($_) } @{ $source->custom_variables };
 | ||
|  | ||
|  | ||
|   my %item_args;
 | ||
|   if (ref($source) eq 'SL::DB::ReclamationItem') {
 | ||
|     map { $item_args{$_} = $source->$_ } qw(
 | ||
|       active_discount_source active_price_source base_qty description discount
 | ||
|       lastcost longdescription parts_id position price_factor price_factor_id
 | ||
|       pricegroup_id project_id qty reason_description_ext reason_description_int
 | ||
|       reason_id reqdate sellprice serialnumber
 | ||
|       unit
 | ||
|     );
 | ||
|     $item_args{custom_variables} = \@custom_variables;
 | ||
|   }
 | ||
|  | ||
|   my $item = $class->new(%item_args);
 | ||
|  | ||
|   if ( $source->record->is_sales() && ($parent_type =~ m{sales}) ) {
 | ||
|     $item->sellprice($source->lastcost);
 | ||
|     $item->discount(0);
 | ||
|   }
 | ||
|   if ( !$source->record->is_sales() && ($parent_type =~ m{purchase}) ) {
 | ||
|     $item->lastcost($source->sellprice);
 | ||
|   }
 | ||
|  | ||
|   $item->assign_attributes(%{ $params{attributes} }) if $params{attributes};
 | ||
|  | ||
|   unless ($params{no_linked_records}) {
 | ||
|     $item->{"converted_from_record_item_type_ref"} = ref($source);
 | ||
|     $item->{"converted_from_record_item_id"} = $source->id;
 | ||
|   }
 | ||
|  | ||
|   return $item;
 | ||
| }
 | ||
|  | ||
| sub _clone_cvar_for_reclamation_item {
 | ||
|   my ($cvar) = @_;
 | ||
|  | ||
|   my $cloned = $_->clone_and_reset;
 | ||
|   $cloned->sub_module('reclamation_items');
 | ||
|  | ||
|   return $cloned;
 | ||
| }
 | ||
|  | ||
| sub customervendor {
 | ||
|   my ($self) = @_;
 | ||
|  | ||
|   return $self->reclamation->customervendor;
 | ||
| }
 | ||
|  | ||
| sub delivered_qty { goto &shipped_qty }
 | ||
| sub record { goto &reclamation }
 | ||
| sub record_id { goto &reclamation_id }
 | ||
| sub trans_id { goto &reclamation_id }
 | ||
| sub date { goto &reqdate }
 | ||
|  | ||
| 1;
 | ||
|  | ||
| __END__
 | ||
|  | ||
| =pod
 | ||
|  | ||
| =head1 NAME
 | ||
|  | ||
| SL::DB::ReclamationItems: Rose model for reclamationitems
 | ||
|  | ||
| =head1 FUNCTIONS
 | ||
|  | ||
| =over 4
 | ||
|  | ||
| =item C<shipped_qty PARAMS>
 | ||
|  | ||
| Calculates the shipped qty for this reclamationitem (measured in the current unit)
 | ||
| and returns it.
 | ||
|  | ||
| Note that the shipped qty is expected not to change within the request and is
 | ||
| cached in C<shipped_qty> once calculated. If C<< force => 1 >> is passed, the
 | ||
| existibng cache is ignored.
 | ||
|  | ||
| Given parameters will be passed to L<SL::Helper::ShippedQty>, so you can force
 | ||
| the shipped/delivered distinction like this:
 | ||
|  | ||
|   $_->shipped_qty(require_stock_out => 0);
 | ||
|  | ||
| Note however that calculating shipped_qty on individual Reclamationitems is generally
 | ||
| a bad idea. See L<SL::Helper::ShippedQty> for way to compute these all at once.
 | ||
|  | ||
| =item C<delivered_qty>
 | ||
|  | ||
| Alias for L</shipped_qty>.
 | ||
|  | ||
| =back
 | ||
|  | ||
| =head1 AUTHORS
 | ||
|  | ||
| G. Richardson E<lt>grichardson@kivitendo-premium.deE<gt>
 | ||
|  | ||
| =cut
 | ||
| SL/DB/ReclamationReason.pm | ||
|---|---|---|
| package SL::DB::ReclamationReason;
 | ||
|  | ||
| use strict;
 | ||
|  | ||
| use SL::DB::MetaSetup::ReclamationReason;
 | ||
| use SL::DB::Manager::ReclamationReason;
 | ||
| use SL::DB::Helper::ActsAsList
 | ||
|  | ||
| __PACKAGE__->meta->initialize;
 | ||
|  | ||
| sub validate {
 | ||
|   my ($self) = @_;
 | ||
|  | ||
|   my @errors;
 | ||
|   if (!$self->name) {
 | ||
|       push @errors, $::locale->text('The name is missing.');
 | ||
|   }
 | ||
|   if (!$self->description) {
 | ||
|     push @errors, $::locale->text('The description is missing.');
 | ||
|   }
 | ||
|   return @errors;
 | ||
| }
 | ||
|  | ||
| 1;
 | ||
| scripts/rose_auto_create_model.pl | ||
|---|---|---|
|     ap                        => { payment_id => 'payment_terms', },
 | ||
|  | ||
|     orderitems                => { parts_id => 'part', trans_id => 'order', },
 | ||
|     reclamation_items         => { parts_id => 'part' },
 | ||
|     delivery_order_items      => { parts_id => 'part' },
 | ||
|     invoice                   => { parts_id => 'part' },
 | ||
|     follow_ups                => { created_by => 'created_by_employee', },
 | ||
| sql/Pg-upgrade2/clean_up_record_links_before_delete_trigger.sql | ||
|---|---|---|
| -- @tag: clean_up_record_links_before_delete_trigger
 | ||
| -- @description: delete trigger for record_links clean up
 | ||
| -- @depends: release_3_5_7
 | ||
|  | ||
| CREATE OR REPLACE FUNCTION clean_up_record_links_before_delete() RETURNS trigger AS $$
 | ||
|   BEGIN
 | ||
|     DELETE FROM record_links
 | ||
|       WHERE (from_table = TG_TABLE_NAME AND from_id = OLD.id)
 | ||
|          OR (to_table   = TG_TABLE_NAME AND to_id   = OLD.id);
 | ||
|     RETURN OLD;
 | ||
|   END;
 | ||
| $$ LANGUAGE plpgsql;
 | ||
| sql/Pg-upgrade2/delete_cvars_on_trans_deletion_add_reclamation_items.sql | ||
|---|---|---|
| -- @tag: delete_cvars_on_trans_deletion_add_reclamation_items
 | ||
| -- @description: Add reclamation_items to trigger
 | ||
| -- @depends: delete_cvars_on_trans_deletion_add_shipto reclamations
 | ||
|  | ||
| CREATE OR REPLACE FUNCTION delete_custom_variables_trigger()
 | ||
| RETURNS TRIGGER AS $$
 | ||
|   BEGIN
 | ||
|     IF (TG_TABLE_NAME IN ('orderitems', 'delivery_order_items', 'invoice', 'reclamation_items')) THEN
 | ||
|       PERFORM delete_custom_variables_with_sub_module('IC', TG_TABLE_NAME, old.id);
 | ||
|     END IF;
 | ||
|  | ||
|     IF (TG_TABLE_NAME = 'parts') THEN
 | ||
|       PERFORM delete_custom_variables_with_sub_module('IC', '', old.id);
 | ||
|     END IF;
 | ||
|  | ||
|     IF (TG_TABLE_NAME IN ('customer', 'vendor')) THEN
 | ||
|       PERFORM delete_custom_variables_with_sub_module('CT', '', old.id);
 | ||
|     END IF;
 | ||
|  | ||
|     IF (TG_TABLE_NAME = 'contacts') THEN
 | ||
|       PERFORM delete_custom_variables_with_sub_module('Contacts', '', old.cp_id);
 | ||
|     END IF;
 | ||
|  | ||
|     IF (TG_TABLE_NAME = 'project') THEN
 | ||
|       PERFORM delete_custom_variables_with_sub_module('Projects', '', old.id);
 | ||
|     END IF;
 | ||
|  | ||
|     IF (TG_TABLE_NAME = 'shipto') THEN
 | ||
|       PERFORM delete_custom_variables_with_sub_module('ShipTo', '', old.shipto_id);
 | ||
|     END IF;
 | ||
|  | ||
|     RETURN old;
 | ||
|   END;
 | ||
| $$ LANGUAGE plpgsql;
 | ||
|  | ||
| CREATE TRIGGER reclamation_items_delete_custom_variables_after_deletion
 | ||
| AFTER DELETE ON reclamation_items
 | ||
| FOR EACH ROW EXECUTE PROCEDURE delete_custom_variables_trigger();
 | ||
| sql/Pg-upgrade2/reclamations.sql | ||
|---|---|---|
| -- @tag: reclamations
 | ||
| -- @description: Add reclamations, reclamation_items and reclamation_reasons
 | ||
| -- @depends: release_3_5_7
 | ||
| -- @ignore: 0
 | ||
|  | ||
| CREATE TABLE reclamation_reasons (
 | ||
|   id                       SERIAL                      PRIMARY KEY,
 | ||
|   name                     TEXT                        NOT NULL,
 | ||
|   description              TEXT                        NOT NULL,
 | ||
|   position                 INTEGER                     NOT NULL,
 | ||
|   itime                    TIMESTAMP without time zone DEFAULT now(),
 | ||
|   mtime                    TIMESTAMP without time zone,
 | ||
|   valid_for_sales          BOOLEAN                     NOT NULL DEFAULT false,
 | ||
|   valid_for_purchase       BOOLEAN                     NOT NULL DEFAULT false
 | ||
| );
 | ||
| CREATE TRIGGER mtime_reclamation_reasons
 | ||
|   BEFORE UPDATE ON reclamation_reasons
 | ||
|   FOR EACH ROW EXECUTE PROCEDURE set_mtime();
 | ||
|  | ||
| CREATE TABLE reclamations (
 | ||
| --basic
 | ||
|   id                      INTEGER                     NOT NULL DEFAULT nextval('id'),
 | ||
|   record_number           TEXT                        NOT NULL,
 | ||
|   transdate               DATE                        DEFAULT now(),
 | ||
|   itime                   TIMESTAMP without time zone DEFAULT now(),
 | ||
|   mtime                   TIMESTAMP without time zone,
 | ||
|   delivered               BOOLEAN                     NOT NULL DEFAULT false,
 | ||
|   closed                  BOOLEAN                     NOT NULL DEFAULT false,
 | ||
| --header
 | ||
|   employee_id             INTEGER                     NOT NULL REFERENCES employee(id),
 | ||
|   globalproject_id        INTEGER                     REFERENCES project(id),
 | ||
|   delivery_term_id        INTEGER                     REFERENCES delivery_terms(id),
 | ||
|   shipto_id               INTEGER                     REFERENCES shipto(shipto_id),
 | ||
|   department_id           INTEGER                     REFERENCES department(id),
 | ||
|   contact_id              INTEGER                     REFERENCES contacts(cp_id),
 | ||
|   shipvia                 TEXT,
 | ||
|   transaction_description TEXT,
 | ||
|   shippingpoint           TEXT,
 | ||
|   cv_record_number        TEXT,
 | ||
|   reqdate                 DATE,
 | ||
| --money/summery
 | ||
|   amount                  NUMERIC(15,5),
 | ||
|   netamount               NUMERIC(15,5),
 | ||
|   payment_id              INTEGER                     REFERENCES payment_terms(id),
 | ||
|   currency_id             INTEGER                     NOT NULL REFERENCES currencies(id),
 | ||
|   taxincluded             BOOLEAN                     NOT NULL,
 | ||
|   tax_point               DATE,
 | ||
|   exchangerate            NUMERIC(15,5),
 | ||
|   taxzone_id              INTEGER                     NOT NULL REFERENCES tax_zones(id),
 | ||
| --other
 | ||
|   notes                   TEXT,
 | ||
|   intnotes                TEXT,
 | ||
|   language_id             INTEGER                     REFERENCES language(id),
 | ||
|  | ||
|   salesman_id             INTEGER                     REFERENCES employee(id),
 | ||
|   customer_id             INTEGER                     REFERENCES customer(id),
 | ||
|  | ||
|   vendor_id               INTEGER                     REFERENCES vendor(id),
 | ||
|  | ||
|   CONSTRAINT reclamations_customervendor_check CHECK (
 | ||
|        (customer_id IS NOT NULL AND vendor_id   IS NULL)
 | ||
|     OR (vendor_id   IS NOT NULL AND customer_id IS NULL)
 | ||
|   ),
 | ||
|  | ||
|   PRIMARY KEY (id)
 | ||
| );
 | ||
| CREATE TRIGGER mtime_reclamations BEFORE UPDATE ON reclamations FOR EACH ROW EXECUTE PROCEDURE set_mtime();
 | ||
|  | ||
| ALTER TABLE defaults ADD COLUMN p_reclamation_record_number TEXT NOT NULL DEFAULT 0;
 | ||
| ALTER TABLE defaults ADD COLUMN s_reclamation_record_number TEXT NOT NULL DEFAULT 0;
 | ||
|  | ||
| CREATE TABLE reclamation_items (
 | ||
| --base
 | ||
|   id                         SERIAL                      PRIMARY KEY,
 | ||
|   reclamation_id             INTEGER                     NOT NULL REFERENCES reclamations(id) ON DELETE CASCADE,
 | ||
|   reason_id                  INTEGER                     NOT NULL REFERENCES reclamation_reasons(id),
 | ||
|   reason_description_ext     TEXT,
 | ||
|   reason_description_int     TEXT,
 | ||
|   position                   INTEGER                     NOT NULL CHECK(position > 0),
 | ||
|   itime                      TIMESTAMP without time zone DEFAULT now(),
 | ||
|   mtime                      TIMESTAMP without time zone,
 | ||
| --header
 | ||
|   project_id                 INTEGER                     REFERENCES project(id) ON DELETE SET NULL,
 | ||
| --part description
 | ||
|   parts_id                   INTEGER                     NOT NULL REFERENCES parts(id),
 | ||
|   description                TEXT,
 | ||
|   longdescription            TEXT,
 | ||
|   serialnumber               TEXT,
 | ||
|   base_qty                   REAL,
 | ||
|   qty                        REAL,
 | ||
|   unit                       character varying(20)       REFERENCES units(name),
 | ||
| --money
 | ||
|   sellprice                  NUMERIC(15,5),
 | ||
|   lastcost                   NUMERIC(15,5),
 | ||
|   discount                   REAL,
 | ||
|   pricegroup_id              INTEGER                     REFERENCES pricegroup(id),
 | ||
|   price_factor_id            INTEGER                     REFERENCES price_factors(id),
 | ||
|   price_factor               NUMERIC(15,5)               DEFAULT 1,
 | ||
|   active_price_source        TEXT                        NOT NULL DEFAULT ''::text,
 | ||
|   active_discount_source     TEXT                        NOT NULL DEFAULT ''::text,
 | ||
| --other
 | ||
|   reqdate                    DATE
 | ||
| );
 | ||
| CREATE TRIGGER mtime_reclamation_items BEFORE UPDATE ON reclamation_items FOR EACH ROW EXECUTE PROCEDURE set_mtime();
 | ||
| sql/Pg-upgrade2/record_links_delete_triggers__reclamations__reclamation_items.sql | ||
|---|---|---|
| -- @tag: record_links_delete_triggers__reclamations__reclamation_items
 | ||
| -- @description: delete corresponding record_links if reclamation or reclamation_item is deleted
 | ||
| -- @depends: clean_up_record_links_before_delete_trigger reclamations
 | ||
|  | ||
| CREATE TRIGGER before_delete_reclamation_items_clean_up_record_linkes_trigger
 | ||
| BEFORE DELETE ON reclamation_items FOR EACH ROW EXECUTE
 | ||
| PROCEDURE clean_up_record_links_before_delete();
 | ||
|  | ||
| CREATE TRIGGER before_delete_reclamations_clean_up_record_linkes_trigger
 | ||
| BEFORE DELETE ON reclamations FOR EACH ROW EXECUTE
 | ||
| PROCEDURE clean_up_record_links_before_delete();
 | ||
Auch abrufbar als: Unified diff
Reclamation: sql-script for data tables and rose objects added