Script, Models und Manager übernommen und angeglichen.
Ein SQL Schema Update, dass die meisten vorausgesetzten Normalisierungen
enthält mit eingefügt.
--- /dev/null
+package SL::DB;
+
+use strict;
+
+use Carp;
+use Data::Dumper;
+use English qw(-no_match_vars);
+use Rose::DB;
+
+use base qw(Rose::DB);
+
+__PACKAGE__->use_private_registry;
+
+my (%_db_registered, %_initial_sql_executed);
+
+sub create {
+ my $domain = shift || SL::DB->default_domain;
+ my $type = shift || SL::DB->default_type;
+
+ if ($type eq 'LXOFFICE') {
+ $domain = 'LXEMPTY' unless %::myconfig && $::myconfig{dbname};
+ $type = join $SUBSCRIPT_SEPARATOR, map { $::myconfig{$_} } qw(dbdriver dbname dbhost dbport dbuser dbpasswd) if %::myconfig;
+ }
+
+ _register_db($domain, $type);
+
+ my $db = __PACKAGE__->new_or_cached(domain => $domain, type => $type);
+
+ return $db;
+}
+
+sub _register_db {
+ my $domain = shift;
+ my $type = shift;
+
+ my $idx = "${domain}::${type}";
+ return if $_db_registered{$idx};
+
+ $_db_registered{$idx} = 1;
+
+ __PACKAGE__->register_db(domain => $domain,
+ type => $type,
+ driver => $::myconfig{dbdriver} || 'Pg',
+ database => $::myconfig{dbname},
+ host => $::myconfig{dbhost},
+ port => $::myconfig{dbport} || 5432,
+ username => $::myconfig{dbuser},
+ password => $::myconfig{dbpasswd},
+ connect_options => { pg_enable_utf8 => $::locale && $::locale->is_utf8,
+ },
+ );
+}
+
+1;
--- /dev/null
+# 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::Assembly;
+
+use strict;
+
+use SL::DB::MetaSetup::Assembly;
+
+__PACKAGE__->meta->add_relationships(
+ part => {
+ type => 'one to one',
+ class => 'SL::DB::Part',
+ column_map => { parts_id => 'id' },
+ },
+);
+
+# Creates get_all, get_all_count, get_all_iterator, delete_all and update_all.
+__PACKAGE__->meta->make_manager_class;
+
+__PACKAGE__->meta->initialize;
+
+1;
--- /dev/null
+# 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::Bin;
+
+use strict;
+
+use SL::DB::MetaSetup::Bin;
+
+# Creates get_all, get_all_count, get_all_iterator, delete_all and update_all.
+__PACKAGE__->meta->make_manager_class;
+
+1;
--- /dev/null
+# 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::Business;
+
+use strict;
+
+use SL::DB::MetaSetup::Business;
+
+__PACKAGE__->attr_percent('discount', places => -2);
+
+# Creates get_all, get_all_count, get_all_iterator, delete_all and update_all.
+__PACKAGE__->meta->make_manager_class;
+
+1;
--- /dev/null
+package SL::DB::Chart;
+
+use strict;
+
+use SL::DB::MetaSetup::Chart;
+
+__PACKAGE__->meta->make_manager_class;
+
+1;
--- /dev/null
+package SL::DB::Customer;
+
+use strict;
+
+use SL::DB::MetaSetup::Customer;
+
+use SL::DB::VC;
+
+__PACKAGE__->meta->add_relationship(
+ shipto => {
+ type => 'one to many',
+ class => 'SL::DB::Shipto',
+ column_map => { id => 'trans_id' },
+ manager_args => { sort_by => 'lower(shipto.shiptoname)' },
+ query_args => [ 'shipto.module' => 'CT' ],
+ },
+ business => {
+ type => 'one to one',
+ class => 'SL::DB::Business',
+ column_map => { business_id => 'id' },
+ },
+);
+
+__PACKAGE__->meta->make_manager_class;
+__PACKAGE__->meta->initialize;
+
+1;
--- /dev/null
+package SL::DB::DeliveryOrder;
+
+use strict;
+
+use SL::DB::MetaSetup::DeliveryOrder;
+use SL::DB::Manager::DeliveryOrder;
+use SL::DB::Order;
+
+use List::Util qw(first);
+
+for my $field (qw(transdate reqdate)) {
+ __PACKAGE__->attr_date($field);
+}
+
+__PACKAGE__->meta->add_relationship(orderitems => { type => 'one to many',
+ class => 'SL::DB::DeliveryOrderItem',
+ column_map => { id => 'trans_id' },
+ manager_args => { with_objects => [ 'part' ] }
+ },
+ );
+
+__PACKAGE__->meta->initialize;
+
+# methods
+
+sub sales_order {
+ my $self = shift;
+ my %params = @_;
+
+ my $orders = SL::DB::Manager::Order->get_all(
+ query => [
+ ordnumber => $self->ordnumber,
+ @{ $params{query} || [] },
+ ],
+ );
+
+ return first { $_->is_type('sales_order') } @{ $orders };
+}
+
+1;
--- /dev/null
+package SL::DB::DeliveryOrderItem;
+
+use strict;
+
+use SL::DB::MetaSetup::DeliveryOrderItem;
+
+for my $field (qw(qty sellprice discount base_qty lastcost price_factor marge_price_factor)) {
+ __PACKAGE__->attr_number($field, places => -2);
+}
+
+__PACKAGE__->meta->make_manager_class;
+
+# methods
+
+sub part {
+ # canonial alias for parts.
+ return shift->parts;
+}
+
+1;
--- /dev/null
+# 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::DeliveryOrderItemsStock;
+
+use strict;
+
+use SL::DB::MetaSetup::DeliveryOrderItemsStock;
+
+for my $field (qw(qty)) {
+ __PACKAGE__->attr_number($field, places => -2);
+}
+
+# Creates get_all, get_all_count, get_all_iterator, delete_all and update_all.
+__PACKAGE__->meta->make_manager_class;
+
+1;
--- /dev/null
+package SL::DB::GLTransaction;
+
+use strict;
+
+use SL::DB::MetaSetup::GLTransaction;
+
+for my $field (qw(transdate gldate)) {
+ __PACKAGE__->attr_date($field);
+}
+
+# Creates get_all, get_all_count, get_all_iterator, delete_all and update_all.
+__PACKAGE__->meta->make_manager_class;
+
+1;
--- /dev/null
+package SL::DB::Helpers::ALL;
+
+use strict;
+
+use SL::DB::Assembly;
+use SL::DB::Bin;
+use SL::DB::Business;
+use SL::DB::Chart;
+use SL::DB::Customer;
+use SL::DB::DeliveryOrder;
+use SL::DB::DeliveryOrderItem;
+use SL::DB::DeliveryOrderItemsStock;
+use SL::DB::GLTransaction;
+use SL::DB::Invoice;
+use SL::DB::InvoiceItem;
+use SL::DB::Order;
+use SL::DB::OrderItem;
+use SL::DB::Part;
+use SL::DB::PriceFactor;
+use SL::DB::Printer;
+use SL::DB::Project;
+use SL::DB::PurchaseInvoice;
+use SL::DB::Shipto;
+use SL::DB::TransferType;
+use SL::DB::Unit;
+use SL::DB::Vendor;
+use SL::DB::Warehouse;
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+SL::DB::Helpers::ALL: Dependency-only package for all SL::DB::* modules
+
+=head1 SYNOPSIS
+
+ use SL::DB::Helpers::ALL;
+
+=head1 DESCRIPTION
+
+This module depends on all modules in SL/DB/*.pm for the convenience
+of being able to write a simple \C<use SL::DB::Helpers::ALL> and
+having everything loaded. This is supposed to be used only in the
+Lx-Office console. Normal modules should C<use> only the modules they
+actually need.
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
+
+=cut
--- /dev/null
+package SL::DB::Helpers::AttrDate;
+
+use strict;
+
+use Carp;
+use English;
+
+sub define {
+ my $package = shift;
+ my $attribute = shift;
+ my %params = @_;
+
+ $params{places} = 2 if !defined($params{places});
+
+ my $code = <<CODE;
+package ${package};
+
+sub ${attribute}_as_date {
+ my \$self = shift;
+
+ if (scalar \@_) {
+ if (\$_[0]) {
+ my (\$yy, \$mm, \$dd) = \$::locale->parse_date(\\\%::myconfig, \@_);
+ \$self->${attribute}(DateTime->new(year => \$yy, month => \$mm, day => \$dd));
+ } else {
+ \$self->${attribute}(undef);
+ }
+ }
+
+ return \$self->${attribute} ? \$::locale->reformat_date({ dateformat => 'yy-mm-dd' }, \$self->${attribute}->ymd, \$::myconfig{dateformat}) : undef;
+}
+
+1;
+CODE
+
+ eval $code;
+ croak "Defining '${attribute}_as_number' failed: $EVAL_ERROR" if $EVAL_ERROR;
+
+ return 1;
+}
+
+1;
--- /dev/null
+package SL::DB::Helpers::AttrNumber;
+
+use strict;
+
+use Carp;
+use English;
+
+sub define {
+ my $package = shift;
+ my $attribute = shift;
+ my %params = @_;
+
+ $params{places} = 2 if !defined($params{places});
+
+ my $code = <<CODE;
+package ${package};
+
+sub ${attribute}_as_number {
+ my \$self = shift;
+
+ if (scalar \@_) {
+ \$self->${attribute}(\$::form->parse_amount(\\\%::myconfig, \$_[0]));
+ }
+
+ return \$::form->format_amount(\\\%::myconfig, \$self->${attribute}, $params{places});
+}
+
+1;
+CODE
+
+ eval $code;
+ croak "Defining '${attribute}_as_number' failed: $EVAL_ERROR" if $EVAL_ERROR;
+
+ return 1;
+}
+
+1;
--- /dev/null
+package SL::DB::Helpers::AttrPercent;
+
+use strict;
+
+use Carp;
+use English;
+
+sub define {
+ my $package = shift;
+ my $attribute = shift;
+ my %params = @_;
+
+ $params{places} = 2 if !defined($params{places});
+
+ my $code = <<CODE;
+package ${package};
+
+sub ${attribute}_as_percent {
+ my \$self = shift;
+
+ if (scalar \@_) {
+ \$self->${attribute}(\$::form->parse_amount(\\\%::myconfig, \$_[0]) / 100);
+ }
+
+ return \$::form->format_amount(\\\%::myconfig, 100 * \$self->${attribute}, $params{places});
+}
+
+1;
+CODE
+
+ eval $code;
+ croak "Defining '${attribute}_as_number' failed: $EVAL_ERROR" if $EVAL_ERROR;
+
+ return 1;
+}
+
+1;
--- /dev/null
+package SL::DB::Helpers::ConventionManager;
+
+use strict;
+
+use Rose::DB::Object::ConventionManager;
+
+use base qw(Rose::DB::Object::ConventionManager);
+
+sub auto_manager_class_name {
+ my $self = shift;
+ my $object_class = shift || $self->meta->class;
+
+ my @parts = split m/::/, $object_class;
+ my $last = pop @parts;
+
+ return join('::', @parts, 'Manager', $last);
+}
+
+# Base name used for 'make_manager_class', e.g. 'get_all',
+# 'update_all'
+sub auto_manager_base_name {
+ return 'all';
+}
+
+sub auto_manager_base_class {
+ return 'SL::DB::Helpers::Manager';
+}
+
+1;
--- /dev/null
+package SL::DB::Helpers::Manager;
+
+use strict;
+
+use Rose::DB::Object::Manager;
+use base qw(Rose::DB::Object::Manager);
+
+sub make_manager_methods {
+ my $class = shift;
+ my @params = scalar(@_) ? @_ : qw(all);
+ return $class->SUPER::make_manager_methods(@params);
+}
+
+sub find_by {
+ my $class = shift;
+
+ return if !@_;
+ return $class->get_all(query => [ @_ ], limit => 1)->[0];
+}
+
+sub get_first {
+ shift->get_all(
+ limit => 1,
+ )->[0];
+}
+
+1;
--- /dev/null
+package SL::DB::Helpers::Mappings;
+
+use strict;
+
+# threse will not be managed as Rose::DB models, because they are not normalized
+# significant changes are needed to get them done.
+my @lxoffice_blacklist_permanent = qw(
+ acc_trans audittrail customertax datev defaults department dpt_trans
+ exchangerate finanzamt follow_up_access gifi inventory leads licenseinvoice
+ makemodel partsgroup partstax prices record_links rmaitems status tax_zones
+ todo_user_config translation translation_payment_terms units_language
+ vendortax);
+
+# these are not managed _yet_, but will hopefully at some point.
+# if you are confident that one of these works, remove it here.
+my @lxoffice_blacklist_temp = qw(
+ bank_accounts buchungsgruppen contacts custom_variable_configs
+ custom_variables custom_variables_validity drafts dunning dunning_config
+ employee follow_up_links follow_ups generic_translations history_erp language
+ license notes payment_terms pricegroup rma schema_info sepa_export
+ sepa_export_items tax taxkeys
+);
+
+my @lxoffice_blacklist = (@lxoffice_blacklist_permanent, @lxoffice_blacklist_temp);
+
+# map table names to their models.
+# unlike rails we have no singular<->plural magic.
+# remeber: tables should be named as the plural of the model name.
+my %lxoffice_package_names = (
+ ar => 'invoice',
+ ap => 'purchase_invoice',
+ delivery_orders => 'delivery_order',
+ delivery_order_items => 'delivery_order_item',
+ gl => 'GLTransaction',
+ invoice => 'invoice_item',
+ orderitems => 'order_item',
+ oe => 'order',
+ parts => 'part',
+ price_factors => 'price_factor',
+ printers => 'Printer',
+ units => 'unit',
+);
+
+sub get_blacklist {
+ return LXOFFICE => \@lxoffice_blacklist;
+}
+
+sub get_package_names {
+ return LXOFFICE => \%lxoffice_package_names;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+SL::DB::Helpers::Mappings - Rose Table <-> Model mapping information
+
+=head1 SYNOPSIS
+
+ use SL::DB::Helpers::Mappings qw(@blacklist %table2model);
+
+=head1 DESCRIPTION
+
+This modul stores table <-> model mappings used by the
+L<scripts/rose_auto_create_model.pl> script. If you add a new table that has
+custom mappings, add it here.
+
+=head1 BUGS
+
+nothing yet
+
+=head1 SEE ALSO
+
+L<scripts/rose_auto_create_model.pl>
+
+=head1 AUTHOR
+
+Sven Schöling <s.schoeling@linet-services.de>
+
+=cut
--- /dev/null
+package SL::DB::Helpers::Metadata;
+
+use strict;
+
+use Rose::DB::Object::Metadata;
+use SL::DB::Helpers::ConventionManager;
+
+use base qw(Rose::DB::Object::Metadata);
+
+sub convention_manager_class {
+ return 'SL::DB::Helpers::ConventionManager';
+}
+
+sub default_manager_base_class {
+ return 'SL::DB::Helpers::Manager';
+}
+
+1;
--- /dev/null
+# 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::Invoice;
+
+use strict;
+
+use List::Util qw(first);
+
+use SL::DB::MetaSetup::Invoice;
+use SL::DB::Manager::Invoice;
+
+__PACKAGE__->attr_number($_, places => -2) for qw(amount netamount paid marge_total marge_percent taxamount);
+__PACKAGE__->attr_date($_) for qw(transdate gldate datepaid duedate deliverydate orddate quodate);
+__PACKAGE__->attr_percent($_) for qw(abschlag_percentage);
+
+__PACKAGE__->meta->add_relationship(
+ invoiceitems => {
+ type => 'one to many',
+ class => 'SL::DB::InvoiceItem',
+ column_map => { id => 'trans_id' },
+ manager_args => {
+ with_objects => [ 'part' ]
+ }
+ },
+);
+
+__PACKAGE__->meta->initialize;
+
+# methods
+
+# it is assumed, that ordnumbers are unique here.
+sub first_order_by_ordnumber {
+ my $self = shift;
+
+ my $orders = SL::DB::Manager::Order->get_all(
+ query => [
+ ordnumber => $self->ordnumber,
+
+ ],
+ );
+
+ return first { $_->is_type('sales_order') } @{ $orders };
+}
+
+sub abschlag_percentage {
+ my $self = shift;
+ my $order = $self->first_order_by_ordnumber or return;
+ my $order_amount = $order->netamount or return;
+ return $self->abschlag
+ ? $self->netamount / $order_amount
+ : undef;
+}
+
+sub taxamount {
+ my $self = shift;
+ die 'not a setter method' if @_;
+
+ return $self->amount - $self->netamount;
+}
+
+1;
--- /dev/null
+package SL::DB::InvoiceItem;
+
+use strict;
+
+use SL::DB::MetaSetup::InvoiceItem;
+
+for my $field (qw(
+ qty allocated sellprice fxsellprice discount base_qty marge_total
+ marge_percent lastcost price_factor marge_price_factor
+)) {
+ __PACKAGE__->attr_number($field, places => -2);
+}
+
+__PACKAGE__->meta->add_relationship(
+ part => {
+ type => 'one to one',
+ class => 'SL::DB::Part',
+ column_map => { parts_id => 'id' },
+ }
+);
+
+# Creates get_all, get_all_count, get_all_iterator, delete_all and update_all.
+__PACKAGE__->meta->make_manager_class;
+
+__PACKAGE__->meta->initialize;
+
+1;
--- /dev/null
+package SL::DB::Manager::DeliveryOrder;
+
+use strict;
+
+use SL::DB::Helpers::Manager;
+use base qw(SL::DB::Helpers::Manager);
+
+sub object_class { 'SL::DB::DeliveryOrder' }
+
+__PACKAGE__->make_manager_methods;
+
+sub type_filter {
+ my $class = shift;
+ my $type = lc(shift || '');
+
+ return ('!customer_id' => undef) if $type eq 'sales_delivery_order';
+ return ('!vendor_id' => undef) if $type eq 'purchase_delivery_order';
+
+ die "Unknown type $type";
+}
+
+1;
--- /dev/null
+package SL::DB::Manager::Invoice;
+
+use strict;
+
+use base qw(SL::DB::Helpers::Manager);
+
+sub object_class { 'SL::DB::Invoice' }
+
+__PACKAGE__->make_manager_methods;
+
+sub type_filter {
+ my $class = shift;
+ my $type = lc(shift || '');
+
+ return (or => [ invoice => 0, invoice => undef ]) if $type eq 'ar_transaction';
+ return (and => [ invoice => 1, amount => { ge => 0 }, or => [ storno => 0, storno => undef ] ]) if $type eq 'invoice';
+ return (and => [ invoice => 1, amount => { lt => 0 }, or => [ storno => 0, storno => undef ] ]) if $type eq 'credit_note';
+ return (and => [ invoice => 1, amount => { lt => 0 }, storno => 1 ]) if $type =~ m/(?:invoice_)?storno/;
+ return (and => [ invoice => 1, amount => { ge => 0 }, storno => 1 ]) if $type eq 'credit_note_storno';
+
+ die "Unknown type $type";
+}
+
+1;
--- /dev/null
+package SL::DB::Manager::Order;
+
+use strict;
+
+use SL::DB::Helpers::Manager;
+use base qw(SL::DB::Helpers::Manager);
+
+sub object_class { 'SL::DB::Order' }
+
+__PACKAGE__->make_manager_methods;
+
+sub type_filter {
+ my $class = shift;
+ my $type = lc(shift || '');
+
+ return (and => [ '!customer_id' => undef, quotation => 1 ]) if $type eq 'sales_quotation';
+ return (and => [ '!vendor_id' => undef, quotation => 1 ]) if $type eq 'request_quotation';
+ return (and => [ '!customer_id' => undef, or => [ quotation => 0, quotation => undef ] ]) if $type eq 'sales_order';
+ return (and => [ '!vendor_id' => undef, or => [ quotation => 0, quotation => undef ] ]) if $type eq 'purchase_order';
+
+ die "Unknown type $type";
+}
+
+1;
--- /dev/null
+package SL::DB::Manager::Part;
+
+use strict;
+
+use SL::DB::Helpers::Manager;
+use base qw(SL::DB::Helpers::Manager);
+
+use Carp;
+use SL::DBUtils;
+
+sub object_class { 'SL::DB::Part' }
+
+__PACKAGE__->make_manager_methods;
+
+sub type_filter {
+ my $class = shift;
+ my $type = lc(shift || '');
+
+ if ($type =~ m/^part/) {
+ return (and => [ or => [ assembly => 0, assembly => undef ],
+ '!inventory_accno_id' => 0,
+ '!inventory_accno_id' => undef,
+ ]);
+
+ } elsif ($type =~ m/^service/) {
+ return (and => [ or => [ assembly => 0, assembly => undef ],
+ or => [ inventory_accno_id => 0, inventory_accno_id => undef ],
+ ]);
+
+ } elsif ($type =~ m/^assembl/) {
+ return (assembly => 1);
+
+ }
+
+ return ();
+}
+
+sub get_ordered_qty {
+ my $class = shift;
+ my @part_ids = @_;
+
+ return () unless @part_ids;
+
+ my $placeholders = join ',', ('?') x @part_ids;
+ my $query = <<SQL;
+ SELECT oi.parts_id, SUM(oi.base_qty) AS qty
+ FROM orderitems oi
+ LEFT JOIN oe ON (oi.trans_id = oe.id)
+ WHERE (oi.parts_id IN ($placeholders))
+ AND (NOT COALESCE(oe.quotation, FALSE))
+ AND (NOT COALESCE(oe.closed, FALSE))
+ AND (NOT COALESCE(oe.delivered, FALSE))
+ AND (COALESCE(oe.vendor_id, 0) <> 0)
+ GROUP BY oi.parts_id
+SQL
+
+ my %qty_by_id = map { $_->{parts_id} => $_->{qty} * 1 } @{ selectall_hashref_query($::form, $class->object_class->init_db->dbh, $query, @part_ids) };
+ map { $qty_by_id{$_} ||= 0 } @part_ids;
+
+ return %qty_by_id;
+}
+
+1;
--- /dev/null
+package SL::DB::Manager::PurchaseInvoice;
+
+use strict;
+
+use SL::DB::Helpers::Manager;
+use base qw(SL::DB::Helpers::Manager);
+
+sub object_class { 'SL::DB::PurchaseInvoice' }
+
+__PACKAGE__->make_manager_methods;
+
+sub type_filter {
+ my $class = shift;
+ my $type = lc(shift || '');
+
+ return (or => [ invoice => 0, invoice => undef ]) if $type eq 'ap_transaction';
+ return (and => [ invoice => 1, or => [ storno => 0, storno => undef ] ]) if $type eq 'invoice';
+ return (and => [ invoice => 1, storno => 1 ]) if $type =~ m/(?:invoice_)?storno/;
+
+ die "Unknown type $type";
+}
+
+1;
--- /dev/null
+package SL::DB::Manager::TransferType;
+
+use strict;
+
+use base qw(SL::DB::Helpers::Manager);
+
+use Carp;
+
+sub object_class { 'SL::DB::TransferType' }
+
+__PACKAGE__->make_manager_methods;
+
+# class functions
+
+sub get_all_in {
+ return shift()->get_all( query => [ direction => 'in', ] );
+}
+
+sub get_all_out {
+ return shift()->get_all( query => [ direction => 'out', ] );
+}
+
+sub get_all_transfer {
+ return shift()->get_all( query => [ direction => 'transfer', ] );
+}
+
+1;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::Assembly;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'assembly',
+
+ columns => [
+ id => { type => 'integer' },
+ parts_id => { type => 'integer' },
+ qty => { type => 'float', precision => 4 },
+ bom => { type => 'boolean' },
+ itime => { type => 'timestamp', default => 'now()' },
+ mtime => { type => 'timestamp' },
+ variable => { type => 'boolean', default => 'false', not_null => 1, remarks => 'true if this part of the assembly is variable, and can be modified' },
+ item_id => { type => 'integer', remarks => 'used to group parts in an assembly for exclusive options' },
+ assembly_id => { type => 'serial', not_null => 1 },
+ ],
+
+ primary_key_columns => [ 'assembly_id' ],
+
+ allow_inline_column_values => 1,
+);
+
+1;
+;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::Bin;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'bin',
+
+ columns => [
+ id => { type => 'integer', not_null => 1, sequence => 'id' },
+ warehouse_id => { type => 'integer', not_null => 1 },
+ description => { type => 'text' },
+ itime => { type => 'timestamp', default => 'now()' },
+ mtime => { type => 'timestamp' },
+ ],
+
+ primary_key_columns => [ 'id' ],
+
+ allow_inline_column_values => 1,
+
+ foreign_keys => [
+ warehouse => {
+ class => 'SL::DB::Warehouse',
+ key_columns => { warehouse_id => 'id' },
+ },
+ ],
+);
+
+1;
+;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::Business;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'business',
+
+ columns => [
+ id => { type => 'integer', not_null => 1, sequence => 'id' },
+ description => { type => 'text' },
+ discount => { type => 'float', precision => 4 },
+ customernumberinit => { type => 'text' },
+ salesman => { type => 'boolean', default => 'false' },
+ itime => { type => 'timestamp', default => 'now()' },
+ mtime => { type => 'timestamp' },
+ ],
+
+ primary_key_columns => [ 'id' ],
+
+ allow_inline_column_values => 1,
+);
+
+1;
+;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::Chart;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'chart',
+
+ columns => [
+ id => { type => 'integer', not_null => 1, sequence => 'id' },
+ accno => { type => 'text', not_null => 1 },
+ description => { type => 'text' },
+ charttype => { type => 'character', default => 'A', length => 1 },
+ category => { type => 'character', length => 1 },
+ link => { type => 'text' },
+ gifi_accno => { type => 'text' },
+ taxkey_id => { type => 'integer' },
+ pos_ustva => { type => 'integer' },
+ pos_bwa => { type => 'integer' },
+ pos_bilanz => { type => 'integer' },
+ pos_eur => { type => 'integer' },
+ datevautomatik => { type => 'boolean', default => 'false' },
+ itime => { type => 'timestamp', default => 'now()' },
+ mtime => { type => 'timestamp' },
+ new_chart_id => { type => 'integer' },
+ valid_from => { type => 'date' },
+ ],
+
+ primary_key_columns => [ 'id' ],
+
+ unique_key => [ 'accno' ],
+
+ allow_inline_column_values => 1,
+);
+
+1;
+;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::Customer;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'customer',
+
+ columns => [
+ id => { type => 'integer', not_null => 1, sequence => 'id' },
+ name => { type => 'varchar', length => 75, not_null => 1 },
+ department_1 => { type => 'varchar', length => 75 },
+ department_2 => { type => 'varchar', length => 75 },
+ street => { type => 'varchar', length => 75 },
+ zipcode => { type => 'varchar', length => 10 },
+ city => { type => 'varchar', length => 75 },
+ country => { type => 'varchar', length => 75 },
+ contact => { type => 'varchar', length => 75 },
+ phone => { type => 'varchar', length => 30 },
+ fax => { type => 'varchar', length => 30 },
+ homepage => { type => 'text' },
+ email => { type => 'text' },
+ notes => { type => 'text' },
+ discount => { type => 'float', precision => 4 },
+ taxincluded => { type => 'boolean' },
+ creditlimit => { type => 'numeric', default => '0', precision => 5, scale => 15 },
+ terms => { type => 'integer', default => '0' },
+ customernumber => { type => 'text' },
+ cc => { type => 'text' },
+ bcc => { type => 'text' },
+ business_id => { type => 'integer' },
+ taxnumber => { type => 'text' },
+ account_number => { type => 'varchar', length => 15 },
+ bank_code => { type => 'varchar', length => 10 },
+ bank => { type => 'text' },
+ language => { type => 'varchar', length => 5 },
+ datevexport => { type => 'integer' },
+ itime => { type => 'timestamp', default => 'now()' },
+ mtime => { type => 'timestamp' },
+ obsolete => { type => 'boolean', default => 'false' },
+ username => { type => 'varchar', length => 50 },
+ user_password => { type => 'text' },
+ salesman_id => { type => 'integer' },
+ c_vendor_id => { type => 'text' },
+ klass => { type => 'integer', default => '0' },
+ language_id => { type => 'integer' },
+ payment_id => { type => 'integer' },
+ taxzone_id => { type => 'integer', default => '0', not_null => 1 },
+ greeting => { type => 'text' },
+ ustid => { type => 'varchar', length => 14 },
+ direct_debit => { type => 'boolean', default => 'false' },
+ iban => { type => 'varchar', length => 100 },
+ bic => { type => 'varchar', length => 100 },
+ ],
+
+ primary_key_columns => [ 'id' ],
+
+ allow_inline_column_values => 1,
+);
+
+1;
+;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::DeliveryOrder;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'delivery_orders',
+
+ columns => [
+ id => { type => 'integer', not_null => 1, sequence => 'id' },
+ donumber => { type => 'text', not_null => 1 },
+ ordnumber => { type => 'text' },
+ transdate => { type => 'date', default => 'now()' },
+ vendor_id => { type => 'integer' },
+ customer_id => { type => 'integer' },
+ reqdate => { type => 'date' },
+ shippingpoint => { type => 'text' },
+ notes => { type => 'text' },
+ intnotes => { type => 'text' },
+ employee_id => { type => 'integer' },
+ closed => { type => 'boolean', default => 'false' },
+ delivered => { type => 'boolean', default => 'false' },
+ cusordnumber => { type => 'text' },
+ oreqnumber => { type => 'text' },
+ department_id => { type => 'integer' },
+ shipvia => { type => 'text' },
+ cp_id => { type => 'integer' },
+ language_id => { type => 'integer' },
+ shipto_id => { type => 'integer' },
+ globalproject_id => { type => 'integer' },
+ salesman_id => { type => 'integer' },
+ transaction_description => { type => 'text' },
+ is_sales => { type => 'boolean' },
+ itime => { type => 'timestamp', default => 'now()' },
+ mtime => { type => 'timestamp' },
+ notes_bottom => { type => 'text' },
+ taxzone_id => { type => 'integer' },
+ taxincluded => { type => 'boolean' },
+ terms => { type => 'integer' },
+ curr => { type => 'character', length => 3 },
+ ],
+
+ primary_key_columns => [ 'id' ],
+
+ allow_inline_column_values => 1,
+
+ foreign_keys => [
+ customer => {
+ class => 'SL::DB::Customer',
+ key_columns => { customer_id => 'id' },
+ },
+
+ globalproject => {
+ class => 'SL::DB::Project',
+ key_columns => { globalproject_id => 'id' },
+ },
+
+ vendor => {
+ class => 'SL::DB::Vendor',
+ key_columns => { vendor_id => 'id' },
+ },
+ ],
+);
+
+1;
+;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::DeliveryOrderItem;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'delivery_order_items',
+
+ columns => [
+ id => { type => 'integer', not_null => 1, sequence => 'delivery_order_items_id' },
+ delivery_order_id => { type => 'integer', not_null => 1 },
+ parts_id => { type => 'integer', not_null => 1 },
+ description => { type => 'text' },
+ qty => { type => 'numeric', precision => 5, scale => 25 },
+ sellprice => { type => 'numeric', precision => 5, scale => 15 },
+ discount => { type => 'float', precision => 4 },
+ project_id => { type => 'integer' },
+ reqdate => { type => 'date' },
+ serialnumber => { type => 'text' },
+ ordnumber => { type => 'text' },
+ transdate => { type => 'text' },
+ cusordnumber => { type => 'text' },
+ unit => { type => 'varchar', length => 20 },
+ base_qty => { type => 'float', precision => 4 },
+ longdescription => { type => 'text' },
+ lastcost => { type => 'numeric', precision => 5, scale => 15 },
+ price_factor_id => { type => 'integer' },
+ price_factor => { type => 'numeric', default => 1, precision => 5, scale => 15 },
+ marge_price_factor => { type => 'numeric', default => 1, precision => 5, scale => 15 },
+ itime => { type => 'timestamp', default => 'now()' },
+ mtime => { type => 'timestamp' },
+ ],
+
+ primary_key_columns => [ 'id' ],
+
+ allow_inline_column_values => 1,
+
+ foreign_keys => [
+ delivery_order => {
+ class => 'SL::DB::DeliveryOrder',
+ key_columns => { delivery_order_id => 'id' },
+ },
+
+ parts => {
+ class => 'SL::DB::Part',
+ key_columns => { parts_id => 'id' },
+ },
+
+ price_factor_obj => {
+ class => 'SL::DB::PriceFactor',
+ key_columns => { price_factor_id => 'id' },
+ },
+
+ project => {
+ class => 'SL::DB::Project',
+ key_columns => { project_id => 'id' },
+ },
+ ],
+);
+
+1;
+;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::DeliveryOrderItemsStock;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'delivery_order_items_stock',
+
+ columns => [
+ id => { type => 'integer', not_null => 1, sequence => 'id' },
+ delivery_order_item_id => { type => 'integer', not_null => 1 },
+ qty => { type => 'numeric', not_null => 1, precision => 5, scale => 15 },
+ unit => { type => 'varchar', length => 20, not_null => 1 },
+ warehouse_id => { type => 'integer', not_null => 1 },
+ bin_id => { type => 'integer', not_null => 1 },
+ chargenumber => { type => 'text' },
+ itime => { type => 'timestamp', default => 'now()' },
+ mtime => { type => 'timestamp' },
+ bestbefore => { type => 'date' },
+ ],
+
+ primary_key_columns => [ 'id' ],
+
+ allow_inline_column_values => 1,
+
+ foreign_keys => [
+ bin => {
+ class => 'SL::DB::Bin',
+ key_columns => { bin_id => 'id' },
+ },
+
+ delivery_order_item => {
+ class => 'SL::DB::DeliveryOrderItem',
+ key_columns => { delivery_order_item_id => 'id' },
+ },
+
+ warehouse => {
+ class => 'SL::DB::Warehouse',
+ key_columns => { warehouse_id => 'id' },
+ },
+ ],
+);
+
+1;
+;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::GLTransaction;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'gl',
+
+ columns => [
+ id => { type => 'integer', not_null => 1, sequence => 'glid' },
+ reference => { type => 'text' },
+ description => { type => 'text' },
+ transdate => { type => 'date', default => 'now' },
+ gldate => { type => 'date', default => 'now' },
+ employee_id => { type => 'integer' },
+ notes => { type => 'text' },
+ department_id => { type => 'integer', default => '0' },
+ taxincluded => { type => 'boolean' },
+ itime => { type => 'timestamp', default => 'now()' },
+ mtime => { type => 'timestamp' },
+ type => { type => 'text' },
+ storno => { type => 'boolean', default => 'false' },
+ storno_id => { type => 'integer' },
+ ob_transaction => { type => 'boolean' },
+ cb_transaction => { type => 'boolean' },
+ ],
+
+ primary_key_columns => [ 'id' ],
+
+ allow_inline_column_values => 1,
+
+ foreign_keys => [
+ storno_obj => {
+ class => 'SL::DB::GLTransaction',
+ key_columns => { storno_id => 'id' },
+ },
+ ],
+);
+
+1;
+;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::Invoice;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'ar',
+
+ columns => [
+ id => { type => 'integer', not_null => 1, sequence => 'glid' },
+ invnumber => { type => 'text', not_null => 1 },
+ transdate => { type => 'date', default => 'now' },
+ gldate => { type => 'date', default => 'now' },
+ customer_id => { type => 'integer' },
+ taxincluded => { type => 'boolean' },
+ amount => { type => 'numeric', precision => 5, scale => 15 },
+ netamount => { type => 'numeric', precision => 5, scale => 15 },
+ paid => { type => 'numeric', precision => 5, scale => 15 },
+ datepaid => { type => 'date' },
+ duedate => { type => 'date' },
+ deliverydate => { type => 'date' },
+ invoice => { type => 'boolean', default => 'false' },
+ shippingpoint => { type => 'text' },
+ terms => { type => 'integer', default => '0' },
+ notes => { type => 'text' },
+ curr => { type => 'character', length => 3 },
+ ordnumber => { type => 'text' },
+ employee_id => { type => 'integer' },
+ quonumber => { type => 'text' },
+ cusordnumber => { type => 'text' },
+ intnotes => { type => 'text' },
+ department_id => { type => 'integer', default => '0' },
+ shipvia => { type => 'text' },
+ itime => { type => 'timestamp', default => 'now()' },
+ mtime => { type => 'timestamp' },
+ cp_id => { type => 'integer' },
+ language_id => { type => 'integer' },
+ payment_id => { type => 'integer' },
+ delivery_customer_id => { type => 'integer' },
+ delivery_vendor_id => { type => 'integer' },
+ storno => { type => 'boolean', default => 'false' },
+ taxzone_id => { type => 'integer' },
+ shipto_id => { type => 'integer' },
+ type => { type => 'text' },
+ dunning_config_id => { type => 'integer' },
+ orddate => { type => 'date' },
+ quodate => { type => 'date' },
+ globalproject_id => { type => 'integer' },
+ salesman_id => { type => 'integer' },
+ transaction_description => { type => 'text' },
+ storno_id => { type => 'integer' },
+ marge_total => { type => 'numeric', precision => 5, scale => 15 },
+ marge_percent => { type => 'numeric', precision => 5, scale => 15 },
+ notes_bottom => { type => 'text' },
+ donumber => { type => 'text' },
+ ],
+
+ primary_key_columns => [ 'id' ],
+
+ allow_inline_column_values => 1,
+
+ foreign_keys => [
+ customer => {
+ class => 'SL::DB::Customer',
+ key_columns => { customer_id => 'id' },
+ },
+
+ globalproject => {
+ class => 'SL::DB::Project',
+ key_columns => { globalproject_id => 'id' },
+ },
+
+ storno_obj => {
+ class => 'SL::DB::Invoice',
+ key_columns => { storno_id => 'id' },
+ },
+ ],
+);
+
+1;
+;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::InvoiceItem;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'invoice',
+
+ columns => [
+ id => { type => 'integer', not_null => 1, sequence => 'invoiceid' },
+ trans_id => { type => 'integer' },
+ parts_id => { type => 'integer' },
+ description => { type => 'text' },
+ qty => { type => 'float', precision => 4 },
+ allocated => { type => 'float', precision => 4 },
+ sellprice => { type => 'numeric', precision => 5, scale => 15 },
+ fxsellprice => { type => 'numeric', precision => 5, scale => 15 },
+ discount => { type => 'float', precision => 4 },
+ assemblyitem => { type => 'boolean', default => 'false' },
+ project_id => { type => 'integer' },
+ deliverydate => { type => 'date' },
+ serialnumber => { type => 'text' },
+ itime => { type => 'timestamp', default => 'now()' },
+ mtime => { type => 'timestamp' },
+ pricegroup_id => { type => 'integer' },
+ ordnumber => { type => 'text' },
+ transdate => { type => 'text' },
+ cusordnumber => { type => 'text' },
+ unit => { type => 'varchar', length => 20 },
+ base_qty => { type => 'float', precision => 4 },
+ subtotal => { type => 'boolean', default => 'false' },
+ longdescription => { type => 'text' },
+ marge_total => { type => 'numeric', precision => 5, scale => 15 },
+ marge_percent => { type => 'numeric', precision => 5, scale => 15 },
+ lastcost => { type => 'numeric', precision => 5, scale => 15 },
+ price_factor_id => { type => 'integer' },
+ price_factor => { type => 'numeric', default => 1, precision => 5, scale => 15 },
+ marge_price_factor => { type => 'numeric', default => 1, precision => 5, scale => 15 },
+ ],
+
+ primary_key_columns => [ 'id' ],
+
+ allow_inline_column_values => 1,
+
+ foreign_keys => [
+ parts => {
+ class => 'SL::DB::Part',
+ key_columns => { parts_id => 'id' },
+ },
+ ],
+);
+
+1;
+;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::Order;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'oe',
+
+ columns => [
+ id => { type => 'integer', not_null => 1, sequence => 'id' },
+ ordnumber => { type => 'text', not_null => 1 },
+ transdate => { type => 'date', default => 'now' },
+ vendor_id => { type => 'integer' },
+ customer_id => { type => 'integer' },
+ amount => { type => 'numeric', precision => 5, scale => 15 },
+ netamount => { type => 'numeric', precision => 5, scale => 15 },
+ reqdate => { type => 'date' },
+ taxincluded => { type => 'boolean' },
+ shippingpoint => { type => 'text' },
+ notes => { type => 'text' },
+ curr => { type => 'character', length => 3 },
+ employee_id => { type => 'integer' },
+ closed => { type => 'boolean', default => 'false' },
+ quotation => { type => 'boolean', default => 'false' },
+ quonumber => { type => 'text' },
+ cusordnumber => { type => 'text' },
+ intnotes => { type => 'text' },
+ department_id => { type => 'integer', default => '0' },
+ itime => { type => 'timestamp', default => 'now()' },
+ mtime => { type => 'timestamp' },
+ shipvia => { type => 'text' },
+ cp_id => { type => 'integer' },
+ language_id => { type => 'integer' },
+ payment_id => { type => 'integer' },
+ delivery_customer_id => { type => 'integer' },
+ delivery_vendor_id => { type => 'integer' },
+ taxzone_id => { type => 'integer' },
+ proforma => { type => 'boolean', default => 'false' },
+ shipto_id => { type => 'integer' },
+ delivered => { type => 'boolean', default => 'false' },
+ globalproject_id => { type => 'integer' },
+ salesman_id => { type => 'integer' },
+ transaction_description => { type => 'text' },
+ marge_total => { type => 'numeric', precision => 5, scale => 15 },
+ marge_percent => { type => 'numeric', precision => 5, scale => 15 },
+ notes_bottom => { type => 'text' },
+ project_manager_id => { type => 'integer' },
+ ],
+
+ primary_key_columns => [ 'id' ],
+
+ allow_inline_column_values => 1,
+
+ foreign_keys => [
+ globalproject => {
+ class => 'SL::DB::Project',
+ key_columns => { globalproject_id => 'id' },
+ },
+ ],
+);
+
+1;
+;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::OrderItem;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'orderitems',
+
+ columns => [
+ trans_id => { type => 'integer' },
+ parts_id => { type => 'integer' },
+ description => { type => 'text' },
+ qty => { type => 'float', precision => 4 },
+ sellprice => { type => 'numeric', precision => 5, scale => 15 },
+ discount => { type => 'float', precision => 4 },
+ project_id => { type => 'integer' },
+ reqdate => { type => 'date' },
+ ship => { type => 'float', precision => 4 },
+ serialnumber => { type => 'text' },
+ id => { type => 'integer', not_null => 1, sequence => 'orderitemsid' },
+ itime => { type => 'timestamp', default => 'now()' },
+ mtime => { type => 'timestamp' },
+ pricegroup_id => { type => 'integer' },
+ ordnumber => { type => 'text' },
+ transdate => { type => 'text' },
+ cusordnumber => { type => 'text' },
+ unit => { type => 'varchar', length => 20 },
+ base_qty => { type => 'float', precision => 4 },
+ subtotal => { type => 'boolean', default => 'false' },
+ longdescription => { type => 'text' },
+ marge_total => { type => 'numeric', precision => 5, scale => 15 },
+ marge_percent => { type => 'numeric', precision => 5, scale => 15 },
+ lastcost => { type => 'numeric', precision => 5, scale => 15 },
+ price_factor_id => { type => 'integer' },
+ price_factor => { type => 'numeric', default => 1, precision => 5, scale => 15 },
+ marge_price_factor => { type => 'numeric', default => 1, precision => 5, scale => 15 },
+ ],
+
+ primary_key_columns => [ 'id' ],
+
+ allow_inline_column_values => 1,
+
+ foreign_keys => [
+ parts => {
+ class => 'SL::DB::Part',
+ key_columns => { parts_id => 'id' },
+ },
+ ],
+);
+
+1;
+;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::Part;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'parts',
+
+ columns => [
+ id => { type => 'integer', not_null => 1, sequence => 'id' },
+ partnumber => { type => 'text', not_null => 1 },
+ description => { type => 'text' },
+ listprice => { type => 'numeric', precision => 5, scale => 15 },
+ sellprice => { type => 'numeric', precision => 5, scale => 15 },
+ lastcost => { type => 'numeric', precision => 5, scale => 15 },
+ priceupdate => { type => 'date', default => 'now' },
+ weight => { type => 'float', precision => 4 },
+ notes => { type => 'text' },
+ makemodel => { type => 'boolean', default => 'false' },
+ assembly => { type => 'boolean', default => 'false' },
+ alternate => { type => 'boolean', default => 'false' },
+ rop => { type => 'float', precision => 4 },
+ inventory_accno_id => { type => 'integer' },
+ income_accno_id => { type => 'integer' },
+ expense_accno_id => { type => 'integer' },
+ bin => { type => 'text' },
+ shop => { type => 'boolean', default => 'false' },
+ obsolete => { type => 'boolean', default => 'false' },
+ bom => { type => 'boolean', default => 'false' },
+ image => { type => 'text' },
+ drawing => { type => 'text' },
+ microfiche => { type => 'text' },
+ partsgroup_id => { type => 'integer' },
+ ve => { type => 'integer' },
+ gv => { type => 'numeric', precision => 5, scale => 15 },
+ itime => { type => 'timestamp', default => 'now()' },
+ mtime => { type => 'timestamp' },
+ unit => { type => 'varchar', length => 20, not_null => 1 },
+ formel => { type => 'text' },
+ not_discountable => { type => 'boolean', default => 'false' },
+ buchungsgruppen_id => { type => 'integer' },
+ payment_id => { type => 'integer' },
+ ean => { type => 'text' },
+ price_factor_id => { type => 'integer' },
+ onhand => { type => 'numeric', default => '0', precision => 5, scale => 25 },
+ stockable => { type => 'boolean', default => 'false' },
+ has_sernumber => { type => 'boolean', default => 'false' },
+ ],
+
+ primary_key_columns => [ 'id' ],
+
+ allow_inline_column_values => 1,
+);
+
+1;
+;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::PriceFactor;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'price_factors',
+
+ columns => [
+ id => { type => 'integer', not_null => 1, sequence => 'id' },
+ description => { type => 'text' },
+ factor => { type => 'numeric', precision => 5, scale => 15 },
+ sortkey => { type => 'integer' },
+ ],
+
+ primary_key_columns => [ 'id' ],
+);
+
+1;
+;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::Printer;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'printers',
+
+ columns => [
+ id => { type => 'integer', not_null => 1, sequence => 'id' },
+ printer_description => { type => 'text', not_null => 1 },
+ printer_command => { type => 'text' },
+ template_code => { type => 'text' },
+ ],
+
+ primary_key_columns => [ 'id' ],
+);
+
+1;
+;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::Project;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'project',
+
+ columns => [
+ id => { type => 'integer', not_null => 1, sequence => 'id' },
+ projectnumber => { type => 'text' },
+ description => { type => 'text' },
+ itime => { type => 'timestamp', default => 'now()' },
+ mtime => { type => 'timestamp' },
+ active => { type => 'boolean', default => 'true' },
+ ],
+
+ primary_key_columns => [ 'id' ],
+
+ unique_key => [ 'projectnumber' ],
+
+ allow_inline_column_values => 1,
+);
+
+1;
+;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::PurchaseInvoice;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'ap',
+
+ columns => [
+ id => { type => 'integer', not_null => 1, sequence => 'glid' },
+ invnumber => { type => 'text', not_null => 1 },
+ transdate => { type => 'date', default => 'now' },
+ gldate => { type => 'date', default => 'now' },
+ vendor_id => { type => 'integer' },
+ taxincluded => { type => 'boolean', default => 'false' },
+ amount => { type => 'numeric', precision => 5, scale => 15 },
+ netamount => { type => 'numeric', precision => 5, scale => 15 },
+ paid => { type => 'numeric', precision => 5, scale => 15 },
+ datepaid => { type => 'date' },
+ duedate => { type => 'date' },
+ invoice => { type => 'boolean', default => 'false' },
+ ordnumber => { type => 'text' },
+ curr => { type => 'character', length => 3 },
+ notes => { type => 'text' },
+ employee_id => { type => 'integer' },
+ quonumber => { type => 'text' },
+ intnotes => { type => 'text' },
+ department_id => { type => 'integer', default => '0' },
+ itime => { type => 'timestamp', default => 'now()' },
+ mtime => { type => 'timestamp' },
+ shipvia => { type => 'text' },
+ cp_id => { type => 'integer' },
+ language_id => { type => 'integer' },
+ payment_id => { type => 'integer' },
+ storno => { type => 'boolean', default => 'false' },
+ taxzone_id => { type => 'integer' },
+ type => { type => 'text' },
+ orddate => { type => 'date' },
+ quodate => { type => 'date' },
+ globalproject_id => { type => 'integer' },
+ transaction_description => { type => 'text' },
+ storno_id => { type => 'integer' },
+ notes_bottom => { type => 'text' },
+ ],
+
+ primary_key_columns => [ 'id' ],
+
+ allow_inline_column_values => 1,
+
+ foreign_keys => [
+ globalproject => {
+ class => 'SL::DB::Project',
+ key_columns => { globalproject_id => 'id' },
+ },
+
+ storno_obj => {
+ class => 'SL::DB::PurchaseInvoice',
+ key_columns => { storno_id => 'id' },
+ },
+
+ vendor => {
+ class => 'SL::DB::Vendor',
+ key_columns => { vendor_id => 'id' },
+ },
+ ],
+);
+
+1;
+;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::Shipto;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'shipto',
+
+ columns => [
+ trans_id => { type => 'integer' },
+ shiptoname => { type => 'varchar', length => 75 },
+ shiptodepartment_1 => { type => 'varchar', length => 75 },
+ shiptodepartment_2 => { type => 'varchar', length => 75 },
+ shiptostreet => { type => 'varchar', length => 75 },
+ shiptozipcode => { type => 'varchar', length => 75 },
+ shiptocity => { type => 'varchar', length => 75 },
+ shiptocountry => { type => 'varchar', length => 75 },
+ shiptocontact => { type => 'varchar', length => 75 },
+ shiptophone => { type => 'varchar', length => 30 },
+ shiptofax => { type => 'varchar', length => 30 },
+ shiptoemail => { type => 'text' },
+ itime => { type => 'timestamp', default => 'now()' },
+ mtime => { type => 'timestamp' },
+ module => { type => 'text' },
+ shipto_id => { type => 'integer', not_null => 1, sequence => 'id' },
+ ],
+
+ primary_key_columns => [ 'shipto_id' ],
+
+ allow_inline_column_values => 1,
+);
+
+1;
+;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::TransferType;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'transfer_type',
+
+ columns => [
+ id => { type => 'integer', not_null => 1, sequence => 'id' },
+ direction => { type => 'varchar', length => 10, not_null => 1 },
+ description => { type => 'text' },
+ sortkey => { type => 'integer' },
+ itime => { type => 'timestamp', default => 'now()' },
+ mtime => { type => 'timestamp' },
+ ],
+
+ primary_key_columns => [ 'id' ],
+
+ allow_inline_column_values => 1,
+);
+
+1;
+;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::Unit;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'units',
+
+ columns => [
+ name => { type => 'varchar', length => 20, not_null => 1 },
+ base_unit => { type => 'varchar', length => 20 },
+ factor => { type => 'numeric', precision => 5, scale => 20 },
+ type => { type => 'varchar', length => 20 },
+ sortkey => { type => 'integer', not_null => 1 },
+ ],
+
+ primary_key_columns => [ 'name' ],
+
+ foreign_keys => [
+ unit => {
+ class => 'SL::DB::Unit',
+ key_columns => { base_unit => 'name' },
+ },
+ ],
+);
+
+1;
+;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::Vendor;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'vendor',
+
+ columns => [
+ id => { type => 'integer', not_null => 1, sequence => 'id' },
+ name => { type => 'varchar', length => 75, not_null => 1 },
+ department_1 => { type => 'varchar', length => 75 },
+ department_2 => { type => 'varchar', length => 75 },
+ street => { type => 'varchar', length => 75 },
+ zipcode => { type => 'varchar', length => 10 },
+ city => { type => 'varchar', length => 75 },
+ country => { type => 'varchar', length => 75 },
+ contact => { type => 'varchar', length => 75 },
+ phone => { type => 'varchar', length => 30 },
+ fax => { type => 'varchar', length => 30 },
+ homepage => { type => 'text' },
+ email => { type => 'text' },
+ notes => { type => 'text' },
+ terms => { type => 'integer', default => '0' },
+ taxincluded => { type => 'boolean' },
+ vendornumber => { type => 'text' },
+ cc => { type => 'text' },
+ bcc => { type => 'text' },
+ gifi_accno => { type => 'text' },
+ business_id => { type => 'integer' },
+ taxnumber => { type => 'text' },
+ discount => { type => 'float', precision => 4 },
+ creditlimit => { type => 'numeric', precision => 5, scale => 15 },
+ account_number => { type => 'varchar', length => 15 },
+ bank_code => { type => 'varchar', length => 10 },
+ bank => { type => 'text' },
+ language => { type => 'varchar', length => 5 },
+ datevexport => { type => 'integer' },
+ itime => { type => 'timestamp', default => 'now()' },
+ mtime => { type => 'timestamp' },
+ obsolete => { type => 'boolean', default => 'false' },
+ username => { type => 'varchar', length => 50 },
+ user_password => { type => 'varchar', length => 12 },
+ salesman_id => { type => 'integer' },
+ v_customer_id => { type => 'text' },
+ language_id => { type => 'integer' },
+ payment_id => { type => 'integer' },
+ taxzone_id => { type => 'integer', default => '0', not_null => 1 },
+ greeting => { type => 'text' },
+ ustid => { type => 'varchar', length => 14 },
+ direct_debit => { type => 'boolean', default => 'false' },
+ iban => { type => 'varchar', length => 100 },
+ bic => { type => 'varchar', length => 100 },
+ ],
+
+ primary_key_columns => [ 'id' ],
+
+ allow_inline_column_values => 1,
+);
+
+1;
+;
--- /dev/null
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by rose_auto_create_model.pl automatically.
+package SL::DB::Warehouse;
+
+use strict;
+
+use base qw(SL::DB::Object);
+
+__PACKAGE__->meta->setup(
+ table => 'warehouse',
+
+ columns => [
+ id => { type => 'integer', not_null => 1, sequence => 'id' },
+ description => { type => 'text' },
+ itime => { type => 'timestamp', default => 'now()' },
+ mtime => { type => 'timestamp' },
+ sortkey => { type => 'integer' },
+ invalid => { type => 'boolean' },
+ ],
+
+ primary_key_columns => [ 'id' ],
+
+ allow_inline_column_values => 1,
+);
+
+1;
+;
--- /dev/null
+package SL::DB::Object;
+
+use strict;
+
+use Readonly;
+use Rose::DB::Object;
+use List::MoreUtils qw(any);
+
+use SL::DB;
+use SL::DB::Helpers::AttrNumber;
+use SL::DB::Helpers::AttrDate;
+use SL::DB::Helpers::AttrPercent;
+use SL::DB::Helpers::Metadata;
+use SL::DB::Helpers::Manager;
+
+use base qw(Rose::DB::Object);
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new();
+
+ $self->_assign_attributes(@_) if $self;
+
+ return $self;
+}
+
+sub init_db {
+ my $class_or_self = shift;
+ my $class = ref($class_or_self) || $class_or_self;
+ my $type = 'LXOFFICE';
+
+ return SL::DB::create(undef, $type);
+}
+
+sub meta_class {
+ return 'SL::DB::Helpers::Metadata';
+}
+
+sub _get_manager_class {
+ my $class_or_self = shift;
+ my $class = ref($class_or_self) || $class_or_self;
+
+ return $class->meta->convention_manager->auto_manager_class_name($class);
+}
+
+Readonly my %text_column_types => (text => 1, char => 1, varchar => 1);
+
+sub assign_attributes {
+ my $self = shift;
+ my %attributes = @_;
+
+ my $pk = ref($self)->meta->primary_key;
+ delete @attributes{$pk->column_names} if $pk;
+
+ return $self->_assign_attributes(%attributes);
+}
+
+sub _assign_attributes {
+ my $self = shift;
+ my %attributes = @_;
+
+ my %types = map { $_->name => $_->type } ref($self)->meta->columns;
+
+ while (my ($attribute, $value) = each %attributes) {
+ my $type = lc($types{$attribute} || 'text');
+ $value = $type eq 'boolean' ? ($value ? 't' : 'f')
+ : $text_column_types{$type} ? $value
+ : ($value || undef);
+ $self->$attribute($value);
+ }
+
+ return $self;
+}
+
+sub update_attributes {
+ my $self = shift;
+
+ $self->assign_attributes(@_)->save;
+
+ return $self;
+}
+
+sub attr_number {
+ SL::DB::Helpers::AttrNumber::define(@_);
+}
+
+sub attr_date {
+ SL::DB::Helpers::AttrDate::define(@_);
+}
+
+sub attr_percent {
+ SL::DB::Helpers::AttrPercent::define(@_);
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+SL::DB::Object: Base class for all of our model classes
+
+=head1 DESCRIPTION
+
+This is the base class from which all other model classes are
+derived. It contains functionality and settings required for all model
+classes.
+
+Several functions (e.g. C<make_manager_class>, C<init_db>) in this
+class are used for setting up the classes / base classes used for all
+model instances. They overwrite the functions from
+L<Rose::DB::Object>.
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item assign_attributes %attributes
+
+=item _assign_attributes %attributes
+
+Assigns all elements from C<%attributes> to the columns by calling
+their setter functions. The difference between the two functions is
+that C<assign_attributes> protects primary key columns while
+C<_assign_attributes> doesn't.
+
+Both functions handle values that are empty strings by replacing them
+with C<undef> for non-text columns. This allows the calling functions
+to use data from HTML forms as the input for C<assign_attributes>
+without having to remove empty strings themselves (think of
+e.g. select boxes with an empty option which should be turned into
+C<NULL> in the database).
+
+=item update_attributes %attributes
+
+Assigns the attributes from C<%attributes> by calling the
+C<assign_attributes> function and saves the object afterwards. Returns
+the object itself.
+
+=item _get_manager_class
+
+Returns the manager package for the object or class that it is called
+on. Can be used from methods in this package for getting the actual
+object's manager.
+
+=back
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
+
+=cut
--- /dev/null
+package SL::DB::Order;
+
+use strict;
+
+use SL::RecordLinks;
+
+use SL::DB::MetaSetup::Order;
+use SL::DB::Manager::Order;
+use SL::DB::Invoice;
+
+__PACKAGE__->attr_number($_, places => -2) for qw(amount netamount marge_total marge_percent);
+__PACKAGE__->attr_date($_) for qw(transdate reqdate);
+
+__PACKAGE__->meta->add_relationship(
+ orderitems => {
+ type => 'one to many',
+ class => 'SL::DB::OrderItem',
+ column_map => { id => 'trans_id' },
+ manager_args => {
+ with_objects => [ 'part' ]
+ }
+ }
+);
+
+__PACKAGE__->meta->initialize;
+
+# methods
+
+sub type {
+ my $self = shift;
+
+ return 'sales_order' if $self->customer_id && ! $self->quotation;
+ return 'purchase_order' if $self->vendor_id && ! $self->quotation;
+ return 'sales_quotation' if $self->customer_id && $self->quotation;
+ return 'request_quotation' if $self->vendor_id && $self->quotation;
+
+ return;
+}
+
+sub is_type {
+ return shift->type eq shift;
+}
+
+sub invoices {
+ my $self = shift;
+ my %params = @_;
+
+ if ($self->quotation) {
+ return [];
+ } else {
+ return SL::DB::Manager::Invoice->get_all(
+ query => [
+ ordnumber => $self->ordnumber,
+ @{ $params{query} || [] },
+ ]
+ );
+ }
+}
+
+sub abschlag_invoices {
+ return shift()->invoices(query => [ abschlag => 1 ]);
+}
+
+sub end_invoice {
+ return shift()->invoices(query => [ abschlag => 0 ]);
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+SL::DB::Order - Order Datenbank Objekt.
+
+=head1 FUNCTIONS
+
+=head2 type
+
+Returns one of the following string types:
+
+=over 4
+
+=item saes_order
+
+=item purchase_order
+
+=item sales_quotation
+
+=item request_quotation
+
+=back
+
+=head2 is_type TYPE
+
+Rreturns true if the order is of the given type.
+
+=head1 BUGS
+
+Nothing here yet.
+
+=head1 AUTHOR
+
+ Sven Schöling <s.schoeling@linet-services.de>
+
+=cut
--- /dev/null
+package SL::DB::OrderItem;
+
+use strict;
+
+use SL::DB::MetaSetup::OrderItem;
+
+__PACKAGE__->meta->add_relationship(
+ part => {
+ type => 'one to one',
+ class => 'SL::DB::Part',
+ column_map => { parts_id => 'id' },
+ }
+);
+
+# Creates get_all, get_all_count, get_all_iterator, delete_all and update_all.
+__PACKAGE__->meta->make_manager_class;
+
+__PACKAGE__->meta->initialize;
+
+sub is_price_update_available {
+ my $self = shift;
+ return $self->origprice > $self->part->sellprice;
+}
+
+1;
--- /dev/null
+package SL::DB::Part;
+
+use strict;
+
+use Carp;
+use SL::DBUtils;
+use SL::DB::MetaSetup::Part;
+use SL::DB::Manager::Part;
+
+__PACKAGE__->attr_number('lastcost', places => -2);
+__PACKAGE__->attr_number('listprice', places => -2);
+__PACKAGE__->attr_number('sellprice', places => -2);
+
+__PACKAGE__->meta->add_relationships(
+ unit_obj => {
+ type => 'one to one',
+ class => 'SL::DB::Unit',
+ column_map => { unit => 'name' },
+ },
+ assemblies => {
+ type => 'one to many',
+ class => 'SL::DB::Assembly',
+ column_map => { id => 'id' },
+ },
+);
+
+__PACKAGE__->meta->initialize;
+
+sub is_type {
+ my $self = shift;
+ my $type = lc(shift || '');
+
+ if ($type =~ m/^part/) {
+ return !$self->assembly && $self->inventory_accno_id ? 1 : 0;
+
+ } elsif ($type =~ m/^service/) {
+ return !$self->inventory_accno_id && !$self->assembly ? 1 : 0;
+
+ } elsif ($type =~ m/^assembl/) {
+ return $self->assembly ? 1 : 0;
+
+ }
+
+ confess "Unknown type parameter '$type'";
+}
+
+sub get_sellprice_info {
+ my $self = shift;
+ my %params = @_;
+
+ confess "Missing part id" unless $self->id;
+
+ my $object = $self->load;
+
+ return { sellprice => $object->sellprice,
+ price_factor_id => $object->price_factor_id };
+}
+
+sub get_ordered_qty {
+ my $self = shift;
+ my %result = SL::DB::Manager::Part->get_ordered_qty($self->id);
+
+ return $result{ $self->id };
+}
+
+sub get_uncommissioned_qty {
+ my $self = shift;
+ my %params = @_;
+
+ confess "Missing part id" unless $self->id;
+
+ my $query = <<SQL;
+ SELECT
+ COALESCE((SELECT SUM(oi.qty)
+ FROM orderitems oi
+ LEFT JOIN oe ON (oi.trans_id = oe.id)
+ WHERE (oi.parts_id = ?)
+ AND (NOT COALESCE(oe.quotation, FALSE))
+ AND (NOT COALESCE(oe.closed, FALSE))
+ AND (NOT COALESCE(oe.delivered, FALSE))
+ AND (COALESCE(oe.customer_id, 0) <> 0)),
+ 0)
+ -
+ COALESCE((SELECT SUM(i.qty) AS qty
+ FROM inventory i
+ LEFT JOIN warehouse wh ON (i.warehouse_id = wh.id)
+ WHERE (i.parts_id = ?)
+ AND COALESCE(wh.commission)),
+ 0)
+ AS qty
+SQL
+
+ my $result = selectfirst_hashref_query($::form, $self->dbh, $query, $self->id, $self->id);
+ return $result ? $result->{qty} : 0;
+}
+
+sub available_units {
+ shift->unit_obj->convertible_units;
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+SL::DB::Part: Model for the 'parts' table
+
+=head1 SYNOPSIS
+
+This is a standard Rose::DB::Object based model and can be used as one.
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item is_type $type
+
+Tests if the current object is a part, a service or an
+assembly. C<$type> must be one of the words 'part', 'service' or
+'assembly' (their plurals are ok, too).
+
+Returns 1 if the requested type matches, 0 if it doesn't and
+C<confess>es if an unknown C<$type> parameter is encountered.
+
+=item get_sellprice_info %params
+
+Retrieves the C<sellprice> and C<price_factor_id> for a part under
+different conditions and returns a hash reference with those two keys.
+
+If C<%params> contains a key C<project_id> then a project price list
+will be consulted if one exists for that project. In this case the
+parameter C<country_id> is evaluated as well: if a price list entry
+has been created for this country then it will be used. Otherwise an
+entry without a country set will be used.
+
+If none of the above conditions is met then the information from
+C<$self> is used.
+
+=item get_ordered_qty %params
+
+Retrieves the quantity that has been ordered from a vendor but that
+has not been delivered yet. Only open purchase orders are considered.
+
+=item get_uncommissioned_qty %params
+
+Retrieves the quantity that has been ordered by a customer but that
+has not been commissioned yet. Only open sales orders are considered.
+
+=back
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
+
+=cut
--- /dev/null
+package SL::DB::PriceFactor;
+
+use strict;
+
+use SL::DB::MetaSetup::PriceFactor;
+
+__PACKAGE__->meta->make_manager_class;
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+SL::DB::PriceFactor: Model for the 'price_factors' table
+
+=head1 SYNOPSIS
+
+This is a standard Rose::DB::Object based model and can be used as one.
+
+=head1 FUNCTIONS
+
+None so far.
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
+
+=cut
--- /dev/null
+package SL::DB::Printer;
+
+use strict;
+
+use SL::DB::MetaSetup::Printer;
+
+__PACKAGE__->meta->make_manager_class;
+
+1;
--- /dev/null
+package SL::DB::Project;
+
+use strict;
+
+use SL::DB::MetaSetup::Project;
+
+__PACKAGE__->meta->make_manager_class;
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+SL::DB::Project: Model for the 'project' table
+
+=head1 SYNOPSIS
+
+This is a standard Rose::DB::Object based model and can be used as one.
+
+=head1 FUNCTIONS
+
+None so far.
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
+
+=cut
--- /dev/null
+package SL::DB::PurchaseInvoice;
+
+use strict;
+
+use SL::DB::MetaSetup::PurchaseInvoice;
+use SL::DB::Manager::PurchaseInvoice;
+
+for my $field (qw(transdate gldate datepaid duedate orddate quodate)) {
+ __PACKAGE__->attr_date($field);
+}
+
+__PACKAGE__->meta->add_relationship(invoiceitems => { type => 'one to many',
+ class => 'SL::DB::InvoiceItem',
+ column_map => { id => 'trans_id' },
+ manager_args => { with_objects => [ 'part' ] }
+ },
+ );
+
+__PACKAGE__->meta->initialize;
+
+1;
--- /dev/null
+package SL::DB::Shipto;
+
+use strict;
+use Readonly;
+
+use SL::DB::MetaSetup::Shipto;
+
+Readonly our @SHIPTO_VARIABLES => qw(shiptoname shiptostreet shiptozipcode shiptocity shiptocountry shiptocontact
+ shiptophone shiptofax shiptoemail shiptodepartment_1 shiptodepartment_2);
+
+__PACKAGE__->meta->make_manager_class;
+
+sub displayable_id {
+ my $self = shift;
+ my $text = join('; ', grep { $_ } (map({ $self->$_ } qw(shiptoname shiptostreet)),
+ join(' ', grep { $_ }
+ map { $self->$_ }
+ qw(shiptozipcode shiptocity))));
+
+ return $text;
+}
+
+1;
--- /dev/null
+# 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::TransferType;
+
+use strict;
+
+use SL::DB::MetaSetup::TransferType;
+use SL::DB::Manager::TransferType;
+
+# methods
+
+sub description_t8 {
+ return $::locale->text(shift()->description);
+}
+
+1;
--- /dev/null
+# 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::Unit;
+
+use strict;
+
+use SL::DB::MetaSetup::Unit;
+
+# Creates get_all, get_all_count, get_all_iterator, delete_all and update_all.
+__PACKAGE__->meta->make_manager_class;
+
+__PACKAGE__->meta->add_relationships(
+ base => {
+ type => 'one to one',
+ class => 'SL::DB::Unit',
+ column_map => { base_unit => 'name' },
+ },
+);
+
+__PACKAGE__->meta->initialize;
+
+#methods
+
+sub unit_class {
+ my $self = shift;
+
+ return $self if !$self->base_unit || $self->name eq $self->base_unit;
+ return $self->base->unit_class;
+}
+
+sub convertible_units {
+ my $self = shift;
+ return [
+ sort { $a->sortkey <=> $b->sortkey }
+ grep { $_->unit_class->name eq $self->unit_class->name }
+ @{ SL::DB::Manager::Unit->get_all }
+ ];
+}
+
+1;
--- /dev/null
+package SL::DB::VC;
+
+use strict;
+
+require Exporter;
+use SL::DBUtils;
+
+our @ISA = qw(Exporter);
+our @EXPORT = qw(get_credit_remaining);
+
+sub get_credit_remaining {
+ my $vc = shift;
+ my ($type, $arap) = ref $vc eq 'SL::DB::Customer' ? ('customer', 'ar') : ('vendor', 'ap');
+ my %params = @_;
+
+ my $credit_remaining = $vc->creditlimit || 0;
+
+ my $query = <<SQL;
+ SELECT SUM(${arap}.amount - ${arap}.paid)
+ FROM ${arap}
+ WHERE ${type}_id = ?
+SQL
+ my ($amount_unpaid) = selectfirst_array_query($::form, $vc->dbh, $query, $vc->id);
+ $credit_remaining -= $amount_unpaid;
+
+ $query = <<SQL;
+ SELECT o.amount,
+ (SELECT e.buy FROM exchangerate e
+ WHERE e.curr = o.curr
+ AND e.transdate = o.transdate)
+ FROM oe o
+ WHERE (o.${type}_id = ?)
+ AND NOT COALESCE(o.quotation, FALSE)
+ AND NOT COALESCE(o.closed, FALSE)
+SQL
+
+ my @values;
+ if ($params{exclude_order_id}) {
+ $query .= qq| AND (o.id <> ?)|;
+ push @values, $params{exclude_order_id};
+ }
+
+ my $sth = prepare_execute_query($::form, $vc->dbh, $query, $vc->id, @values);
+
+ while (my ($amount, $exch) = $sth->fetchrow_array) {
+ $credit_remaining -= $amount * ($exch || 1);
+ }
+ $sth->finish;
+
+ return $credit_remaining;
+}
+
+1;
--- /dev/null
+package SL::DB::Vendor;
+
+use strict;
+
+use SL::DB::MetaSetup::Vendor;
+
+use SL::DB::VC;
+
+__PACKAGE__->meta->add_relationship(
+ shipto => {
+ type => 'one to many',
+ class => 'SL::DB::Shipto',
+ column_map => { id => 'trans_id' },
+ manager_args => { sort_by => 'lower(shipto.shiptoname)' },
+ query_args => [ 'shipto.module' => 'CT' ],
+ },
+ business => {
+ type => 'one to one',
+ class => 'SL::DB::Business',
+ column_map => { business_id => 'id' },
+ },
+);
+
+__PACKAGE__->meta->make_manager_class;
+__PACKAGE__->meta->initialize;
+
+1;
--- /dev/null
+# 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::Warehouse;
+
+use strict;
+
+use SL::DB::MetaSetup::Warehouse;
+use SL::DB::Manager::Warehouse;
+
+__PACKAGE__->meta->add_relationship(
+ bins => {
+ type => 'one to many',
+ class => 'SL::DB::Bin',
+ column_map => { id => 'warehouse_id' },
+ }
+);
+
+# Creates get_all, get_all_count, get_all_iterator, delete_all and update_all.
+#__PACKAGE__->meta->make_manager_class;
+
+__PACKAGE__->meta->initialize;
+
+sub first_bin {
+ return shift()->bins->[0];
+}
+
+1;
--- /dev/null
+#!/usr/bin/perl
+
+use strict;
+
+BEGIN {
+ unshift @INC, "modules/override"; # Use our own versions of various modules (e.g. YAML).
+ push @INC, "modules/fallback"; # Only use our own versions of modules if there's no system version.
+}
+
+use CGI qw( -no_xhtml);
+use Data::Dumper;
+use English qw( -no_match_vars );
+use List::MoreUtils qw(any);
+
+use SL::Auth;
+use SL::DBUtils;
+use SL::DB;
+use SL::Form;
+use SL::Locale;
+use SL::LXDebug;
+use SL::DB::Helpers::ALL;
+use SL::DB::Helpers::Mappings;
+
+our $form;
+our $cgi;
+our $auth;
+
+our $script = __FILE__;
+$script =~ s:.*/::;
+
+$OUTPUT_AUTOFLUSH = 1;
+$Data::Dumper::Sortkeys = 1;
+
+our $meta_path = "SL/DB/MetaSetup";
+
+sub setup {
+ if (@ARGV < 2) {
+ print "Usage: $PROGRAM_NAME login table1[=package1] [table2[=package2] ...]\n";
+ print " or $PROGRAM_NAME login [--all|-a] [--sugar|-s]\n";
+ exit 1;
+ }
+
+ my $login = shift @ARGV;
+
+ $::userspath = "users";
+ $::templates = "templates";
+ $::sendmail = "| /usr/sbin/sendmail -t";
+
+ $::lxdebug = LXDebug->new();
+
+ require "config/lx-erp.conf";
+ require "config/lx-erp-local.conf" if -f "config/lx-erp-local.conf";
+
+ # locale messages
+ $::locale = Locale->new("de");
+ $::form = new Form;
+ $::cgi = new CGI('');
+ $::auth = SL::Auth->new();
+
+ $::user = User->new($login);
+
+ %::myconfig = $auth->read_user($login);
+ $form->{script} = 'rose_meta_data.pl';
+ $form->{login} = $login;
+
+ map { $form->{$_} = $::myconfig{$_} } qw(stylesheet charset);
+
+ mkdir $meta_path unless -d $meta_path;
+}
+
+sub process_table {
+ my @spec = split(/=/, shift, 2);
+ my $table = $spec[0];
+ my $package = ucfirst($spec[1] || $spec[0]);
+ $package =~ s/_+(.)/uc($1)/ge;
+ my $meta_file = "${meta_path}/${package}.pm";
+ my $file = "SL/DB/${package}.pm";
+
+ my $definition = eval <<CODE;
+ package SL::DB::AUTO::$package;
+ use SL::DB::Object;
+ use base qw(SL::DB::Object);
+
+ __PACKAGE__->meta->table('$table');
+ __PACKAGE__->meta->auto_initialize;
+
+ __PACKAGE__->meta->perl_class_definition(indent => 2); # , braces => 'bsd'
+CODE
+
+ if ($EVAL_ERROR) {
+ print STDERR "Error in execution for table '$table': $EVAL_ERROR";
+ return;
+ }
+
+ $definition =~ s/::AUTO::/::/g;
+
+ my $file_exists = -f $meta_file;
+
+ open(OUT, ">$meta_file") || die;
+ print OUT <<CODE;
+# This file has been auto-generated. Do not modify it; it will be overwritten
+# by $::script automatically.
+$definition;
+CODE
+ close OUT;
+
+ print "File '$meta_file' " . ($file_exists ? 'updated' : 'created') . " for table '$table'\n";
+
+ if (! -f $file) {
+ open(OUT, ">$file") || die;
+ print OUT <<CODE;
+# 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::${package};
+
+use strict;
+
+use SL::DB::MetaSetup::${package};
+
+# Creates get_all, get_all_count, get_all_iterator, delete_all and update_all.
+__PACKAGE__->meta->make_manager_class;
+
+1;
+CODE
+ close OUT;
+
+ print "File '$file' created as well.\n";
+ }
+}
+
+setup();
+
+my %blacklist = SL::DB::Helpers::Mappings->get_blacklist;
+my %package_names = SL::DB::Helpers::Mappings->get_package_names;
+
+my @tables = ();
+if (($ARGV[0] eq '--all') || ($ARGV[0] eq '-a') || ($ARGV[0] eq '--sugar') || ($ARGV[0] eq '-s')) {
+ my ($type, $prefix) = ($ARGV[0] eq '--sugar') || ($ARGV[0] eq '-s') ? ('SUGAR', 'sugar_') : ('LXOFFICE', '');
+ my $db = SL::DB::create(undef, $type);
+ @tables = map { $package_names{$type}->{$_} ? "${_}=" . $package_names{$type}->{$_} : $prefix ? "${_}=${prefix}${_}" : $_ }
+ grep { my $table = $_; !any { $_ eq $table } @{ $blacklist{$type} } }
+ $db->list_tables;
+
+} else {
+ @tables = @ARGV;
+}
+
+foreach my $table (@tables) {
+ # add default model name unless model name is given or no defaults exists
+ $table .= '=' . $package_names{LXOFFICE}->{lc $table} if $table !~ /=/ && $package_names{LXOFFICE}->{lc $table};
+
+ process_table($table);
+}
--- /dev/null
+-- @tag: schema_normalization_1
+-- @description: Datenbankschema Normalisierungen
+-- @depends: release_2_6_1
+
+-- assembly-id
+CREATE SEQUENCE assembly_assembly_id_seq;
+ALTER TABLE assembly ADD COLUMN assembly_id INTEGER;
+UPDATE assembly SET assembly_id = nextval('assembly_assembly_id_seq');
+ALTER TABLE assembly ADD PRIMARY KEY( assembly_id );
+ALTER TABLE assembly ALTER assembly_id SET DEFAULT nextval('assembly_assembly_id_seq');
+
+-- shipto_primary_key
+ALTER TABLE shipto ALTER COLUMN shipto_id SET NOT NULL;
+ALTER TABLE shipto ADD PRIMARY KEY (shipto_id);
+
+-- oe_vc_foreign_keys
+--ALTER TABLE oe ADD FOREIGN KEY (customer_id) REFERENCES customer (id);
+--ALTER TABLE oe ADD FOREIGN KEY (vendor_id) REFERENCES vendor (id);
+
+-- orderitems_primary_key
+ALTER TABLE orderitems ADD PRIMARY KEY (id);
+
+-- part_unit_not_null
+UPDATE parts SET unit = 'Stck' WHERE unit IS NULL;
+ALTER TABLE parts ALTER COLUMN unit SET NOT NULL;
+
+-- makemodel_id_column
+ALTER TABLE makemodel ADD COLUMN tmp integer;
+UPDATE makemodel SET tmp = make::integer WHERE COALESCE(make, '') <> '';
+ALTER TABLE makemodel DROP COLUMN make;
+ALTER TABLE makemodel RENAME COLUMN tmp TO make;
+
+CREATE SEQUENCE makemodel_id_seq;
+ALTER TABLE makemodel ADD COLUMN id integer;
+ALTER TABLE makemodel ALTER COLUMN id SET DEFAULT nextval('makemodel_id_seq');
+UPDATE makemodel SET id = nextval('makemodel_id_seq');
+ALTER TABLE makemodel ALTER COLUMN id SET NOT NULL;
+ALTER TABLE makemodel ADD PRIMARY KEY (id);