From: Moritz Bunkus Date: Thu, 30 Dec 2010 15:57:11 +0000 (+0100) Subject: Merge branch 'master' of ssh://lx-office.linet-services.de/~/lx-office-erp X-Git-Tag: release-2.6.2beta1~17^2 X-Git-Url: http://wagnertech.de/git?a=commitdiff_plain;h=10150f2fb96a248c46b65cea5859d7f1dd11340e;hp=7b162f9b3b7aefffcc9725b74c3589571d47aa8e;p=kivitendo-erp.git Merge branch 'master' of ssh://lx-office.linet-services.de/~/lx-office-erp --- diff --git a/SL/DB/Helper/ALL.pm b/SL/DB/Helper/ALL.pm new file mode 100644 index 000000000..50f4b3db7 --- /dev/null +++ b/SL/DB/Helper/ALL.pm @@ -0,0 +1,107 @@ +package SL::DB::Helper::ALL; + +use strict; + +use SL::DB::AccTrans; +use SL::DB::AccTransaction; +use SL::DB::Assembly; +use SL::DB::AuditTrail; +use SL::DB::BankAccount; +use SL::DB::Bin; +use SL::DB::Buchungsgruppe; +use SL::DB::Business; +use SL::DB::Chart; +use SL::DB::Contact; +use SL::DB::CustomVariable; +use SL::DB::CustomVariableConfig; +use SL::DB::CustomVariableValidity; +use SL::DB::Customer; +use SL::DB::CustomerTax; +use SL::DB::Datev; +use SL::DB::Default; +use SL::DB::DeliveryOrder; +use SL::DB::DeliveryOrderItem; +use SL::DB::DeliveryOrderItemsStock; +use SL::DB::Department; +use SL::DB::DptTrans; +use SL::DB::Draft; +use SL::DB::Dunning; +use SL::DB::DunningConfig; +use SL::DB::Employee; +use SL::DB::Exchangerate; +use SL::DB::Finanzamt; +use SL::DB::FollowUp; +use SL::DB::FollowUpAccess; +use SL::DB::FollowUpLink; +use SL::DB::GLTransaction; +use SL::DB::GenericTranslation; +use SL::DB::Gifi; +use SL::DB::History; +use SL::DB::Inventory; +use SL::DB::Invoice; +use SL::DB::InvoiceItem; +use SL::DB::Language; +use SL::DB::License; +use SL::DB::LicenseInvoice; +use SL::DB::MakeModel; +use SL::DB::Note; +use SL::DB::Order; +use SL::DB::OrderItem; +use SL::DB::Part; +use SL::DB::PartsGroup; +use SL::DB::PartsTax; +use SL::DB::PaymentTerm; +use SL::DB::PriceFactor; +use SL::DB::Pricegroup; +use SL::DB::Prices; +use SL::DB::Printer; +use SL::DB::Project; +use SL::DB::PurchaseInvoice; +use SL::DB::RMA; +use SL::DB::RMAItem; +use SL::DB::RecordLink; +use SL::DB::SchemaInfo; +use SL::DB::SepaExport; +use SL::DB::SepaExportItem; +use SL::DB::Shipto; +use SL::DB::Status; +use SL::DB::Tax; +use SL::DB::TaxKey; +use SL::DB::TaxZone; +use SL::DB::TodoUserConfig; +use SL::DB::TransferType; +use SL::DB::Translation; +use SL::DB::TranslationPaymentTerm; +use SL::DB::Unit; +use SL::DB::UnitsLanguage; +use SL::DB::Vendor; +use SL::DB::VendorTax; +use SL::DB::Warehouse; + +1; + +__END__ + +=pod + +=head1 NAME + +SL::DB::Helper::ALL: Dependency-only package for all SL::DB::* modules + +=head1 SYNOPSIS + + use SL::DB::Helper::ALL; + +=head1 DESCRIPTION + +This module depends on all modules in SL/DB/*.pm for the convenience +of being able to write a simple \C and +having everything loaded. This is supposed to be used only in the +Lx-Office console. Normal modules should C only the modules they +actually need. + +=head1 AUTHOR + +Moritz Bunkus Em.bunkus@linet-services.deE + +=cut diff --git a/SL/DB/Helper/Attr.pm b/SL/DB/Helper/Attr.pm new file mode 100644 index 000000000..463bfd654 --- /dev/null +++ b/SL/DB/Helper/Attr.pm @@ -0,0 +1,135 @@ +package SL::DB::Helper::Attr; + +use strict; + +sub auto_make { + my ($package, %params) = @_; + + for my $col ($package->meta->columns) { + next if $col->primary_key_position; # don't make attr helper for primary keys + _make_by_type($package, $col->name, $col->type); + } + + return $package; +} + +sub make { + my ($package, %params) = @_; + + for my $name (keys %params) { + my @types = ref $params{$name} eq 'ARRAY' ? @{ $params{$name} } : ($params{$name}); + for my $type (@types) { + _make_by_type($package, $name, $type); + } + } + return $package; +} + + + +sub _make_by_type { + my ($package, $name, $type) = @_; + _as_number ($package, $name, places => -2) if $type =~ /numeric | real | float/xi; + _as_percent($package, $name, places => 0) if $type =~ /numeric | real | float/xi; + _as_number ($package, $name, places => 0) if $type =~ /int/xi; + _as_date ($package, $name) if $type =~ /date | timestamp/xi; +} + +sub _as_number { + my $package = shift; + my $attribute = shift; + my %params = @_; + + $params{places} = 2 if !defined($params{places}); + + no strict 'refs'; + *{ $package . '::' . $attribute . '_as_number' } = sub { + my ($self, $string) = @_; + + $self->$attribute($::form->parse_amount(\%::myconfig, $string)) if @_ > 1; + + return $::form->format_amount(\%::myconfig, $self->$attribute, $params{places}); + }; +} + +sub _as_percent { + my $package = shift; + my $attribute = shift; + my %params = @_; + + $params{places} = 2 if !defined($params{places}); + + no strict 'refs'; + *{ $package . '::' . $attribute . '_as_percent' } = sub { + my ($self, $string) = @_; + + $self->$attribute($::form->parse_amount(\%::myconfig, $string) / 100) if @_ > 1; + + return $::form->format_amount(\%::myconfig, 100 * $self->$attribute, $params{places}); + }; + + return 1; +} + +sub _as_date { + my $package = shift; + my $attribute = shift; + my %params = @_; + + no strict 'refs'; + *{ $package . '::' . $attribute . '_as_date' } = sub { + my ($self, $string) = @_; + + if (@_ > 1) { + if ($string) { + my ($yy, $mm, $dd) = $::locale->parse_date(\%::myconfig, $string); + $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 eq 'now' + ? DateTime->now + : $self->$attribute + )->ymd, + $::myconfig{dateformat} + ) + : undef; + }; + + return 1; +} + +1; + + +1; + +__END__ + +=head1 NAME + +SL::DB::Helper::Attr - attribute helpers + +=head1 SYNOPSIS + + use SL::DB::Helper::Attr; + SL::DB::Helper::Attr::make($class, + method_name => 'numeric(15,5)', + datemethod => 'date' + ); + SL::DB::Helper::Attr::auto_make($class); + +=head1 DESCRIPTION + +=head1 FUNCTIONS + +=head1 BUGS + +=head1 AUTHOR + +=cut diff --git a/SL/DB/Helper/ConventionManager.pm b/SL/DB/Helper/ConventionManager.pm new file mode 100644 index 000000000..35c6b1ef2 --- /dev/null +++ b/SL/DB/Helper/ConventionManager.pm @@ -0,0 +1,29 @@ +package SL::DB::Helper::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::Helper::Manager'; +} + +1; diff --git a/SL/DB/Helper/Manager.pm b/SL/DB/Helper/Manager.pm new file mode 100644 index 000000000..529053338 --- /dev/null +++ b/SL/DB/Helper/Manager.pm @@ -0,0 +1,27 @@ +package SL::DB::Helper::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; diff --git a/SL/DB/Helper/Mappings.pm b/SL/DB/Helper/Mappings.pm new file mode 100644 index 000000000..48c486307 --- /dev/null +++ b/SL/DB/Helper/Mappings.pm @@ -0,0 +1,187 @@ +package SL::DB::Helpers::Mappings; + +use utf8; +use strict; + +# these will not be managed as Rose::DB models, because they are not normalized, +# significant changes are needed to get them done, or they were done by CRM. +my @lxoffice_blacklist_permanent = qw( + leads +); + +# 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( +); + +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 = ( + acc_trans => 'acc_transaction', + audittrail => 'audit_trail', + ar => 'invoice', + ap => 'purchase_invoice', + bank_accounts => 'bank_account', + buchungsgruppen => 'buchungsgruppe', + contacts => 'contact', + custom_variable_configs => 'custom_variable_config', + custom_variables => 'custom_variable', + custom_variables_validity => 'custom_variable_validity', + customertax => 'customer_tax', + datev => 'datev', + defaults => 'default', + delivery_orders => 'delivery_order', + delivery_order_items => 'delivery_order_item', + department => 'department', + dpt_trans => 'dpt_trans', + drafts => 'draft', + dunning => 'dunning', + dunning_config => 'dunning_config', + employee => 'employee', + exchangerate => 'exchangerate', + finanzamt => 'finanzamt', + follow_up_access => 'follow_up_access', + follow_up_links => 'follow_up_link', + follow_ups => 'follow_up', + generic_translations => 'generic_translation', + gifi => 'gifi', + gl => 'GLTransaction', + history_erp => 'history', + inventory => 'inventory', + invoice => 'invoice_item', + language => 'language', + license => 'license', + licenseinvoice => 'license_invoice', + makemodel => 'make_model', + notes => 'note', + orderitems => 'order_item', + oe => 'order', + parts => 'part', + partsgroup => 'parts_group', + partstax => 'parts_tax', + payment_terms => 'payment_term', + prices => 'prices', + price_factors => 'price_factor', + pricegroup => 'pricegroup', + printers => 'Printer', + record_links => 'record_link', + rma => 'RMA', + rmaitems => 'RMA_item', + sepa_export => 'sepa_export', + sepa_export_items => 'sepa_export_item', + schema_info => 'schema_info', + status => 'status', + tax => 'tax', + taxkeys => 'tax_key', + tax_zones => 'tax_zone', + todo_user_config => 'todo_user_config', + translation => 'translation', + translation_payment_terms => 'translation_payment_term', + units => 'unit', + units_language => 'units_language', + vendortax => 'vendor_tax', +); + +sub get_blacklist { + return LXOFFICE => \@lxoffice_blacklist; +} + +sub get_package_names { + return LXOFFICE => \%lxoffice_package_names; +} + +sub db { + my $string = $_[0]; + my $lookup = $lxoffice_package_names{$_[0]} || + plurify($lxoffice_package_names{singlify($_[0])}); + + for my $thing ($string, $lookup) { + + # best guess? its already the name. like part. camelize it first + my $class = "SL::DB::" . camelify($thing); + return $class if defined *{ $class. '::' }; + + # next, someone wants a manager and pluralized. + my $manager = "SL::DB::Manager::" . singlify(camelify($thing)); + return $manager if defined *{ $manager . '::' }; + } + + die "Can't resolve '$string' as a database model, sorry. Did you perhaps forgot to load it?"; +} + +sub camelify { + my ($str) = @_; + $str =~ s/_+(.)/uc($1)/ge; + ucfirst $str; +} + +sub snakify { + my ($str) = @_; + $str =~ s/(? 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 script. If you add a new table that has +custom mappings, add it here. + +=head2 db + +A special function provided here is E. Without it you'd have to write: + + my $part = SL::DB::Part->new(id => 1234); + my @all_parts = SL::DB::Manager::Part->get_all; + +with them it becomes: + + my $part = db('part')->new(id => 123); + my @all_parts = db('parts')->get_all; + +You don't have to care about add that SL::DB:: incantation anymore. Also, a +simple s at the end will get you the associated Manager class. + +db is written to try to make sense of what you give it, but if all fails, it +will die with an error. + +=head1 BUGS + +nothing yet + +=head1 SEE ALSO + +L + +=head1 AUTHOR + +Sven Schöling + +=cut diff --git a/SL/DB/Helper/Metadata.pm b/SL/DB/Helper/Metadata.pm new file mode 100644 index 000000000..9ce1f1192 --- /dev/null +++ b/SL/DB/Helper/Metadata.pm @@ -0,0 +1,34 @@ +package SL::DB::Helper::Metadata; + +use strict; + +use Rose::DB::Object::Metadata; +use SL::DB::Helper::ConventionManager; + +use base qw(Rose::DB::Object::Metadata); + +sub convention_manager_class { + return 'SL::DB::Helper::ConventionManager'; +} + +sub default_manager_base_class { + return 'SL::DB::Helper::Manager'; +} + +sub initialize { + my $self = shift; + $self->make_attr_auto_helpers unless $self->is_initialized; + $self->SUPER::initialize(@_); +} + +sub make_attr_helpers { + my ($self, %params) = @_; + SL::DB::Helper::Attr::make($self->class, %params); +} + +sub make_attr_auto_helpers { + my ($self) = @_; + SL::DB::Helper::Attr::auto_make($self->class); +} + +1; diff --git a/SL/DB/Helper/Sorted.pm b/SL/DB/Helper/Sorted.pm new file mode 100644 index 000000000..9442c842e --- /dev/null +++ b/SL/DB/Helper/Sorted.pm @@ -0,0 +1,226 @@ +package SL::DB::Helper::Sorted; + +use strict; + +require Exporter; +our @ISA = qw(Exporter); +our @EXPORT = qw(get_all_sorted make_sort_string); + +my %sort_spec; + +sub make_sort_string { + my ($class, %params) = @_; + + my $sort_spec = _get_sort_spec($class); + + my $sort_dir = defined($params{sort_dir}) ? $params{sort_dir} * 1 : $sort_spec->{default}->[1]; + my $sort_dir_str = $sort_dir ? 'ASC' : 'DESC'; + + my $sort_by = $params{sort_by}; + $sort_by = $sort_spec->{default}->[0] unless $sort_spec->{columns}->{$sort_by}; + + my $nulls_str = ''; + if ($sort_spec->{nulls}) { + $nulls_str = ref($sort_spec->{nulls}) ? ($sort_spec->{nulls}->{$sort_by} || $sort_spec->{nulls}->{default}) : $sort_spec->{nulls}; + $nulls_str = " NULLS ${nulls_str}" if $nulls_str; + } + + my $sort_by_str = $sort_spec->{columns}->{$sort_by}; + $sort_by_str = [ $sort_by_str ] unless ref($sort_by_str) eq 'ARRAY'; + $sort_by_str = join(', ', map { "${_} ${sort_dir_str}${nulls_str}" } @{ $sort_by_str }); + + return wantarray ? ($sort_by, $sort_dir, $sort_by_str) : $sort_by_str; +} + +sub get_all_sorted { + my ($class, %params) = @_; + my $sort_str = $class->make_sort_string(sort_by => delete($params{sort_by}), sort_dir => delete($params{sort_dir})); + + return $class->get_all(sort_by => $sort_str, %params); +} + +sub _get_sort_spec { + my ($class) = @_; + return $sort_spec{$class} ||= _make_sort_spec($class); +} + +sub _make_sort_spec { + my ($class) = @_; + + my %sort_spec = $class->_sort_spec if defined &{ "${class}::_sort_spec" }; + + my $meta = $class->object_class->meta; + + if (!$sort_spec{default}) { + my @primary_keys = $meta->primary_key; + $sort_spec{default} = [ "" . $primary_keys[0], 1 ]; + } + + $sort_spec{columns} ||= { SIMPLE => [ map { "$_" } $meta->columns ] }; + + if ($sort_spec{columns}->{SIMPLE}) { + my $table = $meta->table; + + if (!ref($sort_spec{columns}->{SIMPLE}) && ($sort_spec{columns}->{SIMPLE} eq 'ALL')) { + map { $sort_spec{columns}->{"$_"} ||= "${table}.${_}"} @{ $meta->columns }; + delete $sort_spec{columns}->{SIMPLE}; + } else { + map { $sort_spec{columns}->{$_} = "${table}.${_}" } @{ delete($sort_spec{columns}->{SIMPLE}) }; + } + } + + return \%sort_spec; +} + +1; + +__END__ + +=encoding utf8 + +=head1 NAME + +SL::DB::Helper::Sorted - Mixin for a manager class that handles +sorting of database records + +=head1 SYNOPSIS + + package SL::DB::Manager::Message; + + use SL::DB::Helper::Sorted; + + sub _sort_spec { + return ( columns => { recipient_id => [ 'CASE + WHEN recipient_group_id IS NULL THEN lower(recipient.name) + ELSE lower(recipient_group.name) + END', ], + sender_id => [ 'lower(sender.name)', ], + created_at => [ 'created_at', ], + subject => [ 'lower(subject)', ], + status => [ 'NOT COALESCE(unread, FALSE)', 'created_at' ], + }, + default => [ 'status', 1 ], + nulls => { default => 'LAST', + subject => 'FIRST', + } + ); + } + + package SL::Controller::Message; + + sub action_list { + my $messages = SL::DB::Manager::Message->get_all_sorted(sort_by => $::form->{sort_by}, + sort_dir => $::form->{sort_dir}); + } + +=head1 CLASS FUNCTIONS + +=over 4 + +=item C + +Evaluates C<$params{sort_by}> and C<$params{sort_dir}> and returns an +SQL string suitable for sorting. The package this package is mixed +into has to provide a method L that returns a hash whose +structure is explained below. That hash is authoritive in which +columns may be sorted, which column to sort by by default and how to +handle C values. + +Returns the SQL string in scalar context. In array context it returns +three values: the actual column it sorts by (suitable for another call +to L), the actual sort direction (either 0 or 1) +and the SQL string. + +=item C + +Returns C<< $class->get_all >> with C set to the value +returned by c<< $class->make_sort_string(%params) >>. + +=back + +=head1 CLASS FUNCTIONS PROVIDED BY THE MIXING PACKAGE + +=over 4 + +=item C<_sort_spec> + +This method is actually not part of this package but can be provided +by the package this helper is mixed into. If it isn't then all columns +of the corresponding table (as returned by the model's meta data) will +be eligible for sorting. + +Returns a hash with the following keys: + +=over 2 + +=item C + +A two-element array containing the name and direction by which to sort +in default cases. Example: + + default => [ 'name', 1 ], + +Defaults to the table's primary key column (the first column if the +primary key is composited). + +=item C + +A hash reference. Its keys are column names, and its values are SQL +strings by which to sort. Example: + + columns => { SIMPLE => [ 'transaction_description', 'orddate' ], + the_date => 'CASE WHEN oe.quotation THEN oe.quodate ELSE oe.orddate END', + customer_name => 'lower(customer.name)', + }, + +If sorting by a column is requested that is not a key in this hash +then the default column name will be used. + +The value can be either a scalar or an array reference. If it's the +latter then both the sort direction as well as the null handling will +be appended to each of its members. + +The special key C can be a scalar or an array reference. If it +is an array reference then it contains column names that are mapped +1:1 onto the table's columns. If it is the scalar 'ALL' then all +columns in that model's meta data are mapped 1:1 unless the C +hash already contains a key for that column. + +If C is missing then all columns of the model will be +eligible for sorting. The list of columns is looked up in the model's +meta data. + +=item C + +Either a scalar or a hash reference determining where C values +will be sorted. If undefined then the decision is left to the +database. + +If it is a scalar then all the same value will be used for all +classes. The value is either C or C. + +If it is a hash reference then its keys are column names (not SQL +names). The values are either C or C. If a column name is +not found in this hash then the special keu C will be looked +up and used if it is found. + +Example: + + nulls => { transaction_description => 'FIRST', + customer_name => 'FIRST', + default => 'LAST', + }, + +=back + +=back + +=head1 BUGS + +Nothing here yet. + +=head1 AUTHOR + +Moritz Bunkus Em.bunkus@linet-services.deE + +=cut diff --git a/SL/DB/Helpers/ALL.pm b/SL/DB/Helpers/ALL.pm deleted file mode 100644 index 16184c5a1..000000000 --- a/SL/DB/Helpers/ALL.pm +++ /dev/null @@ -1,107 +0,0 @@ -package SL::DB::Helpers::ALL; - -use strict; - -use SL::DB::AccTrans; -use SL::DB::AccTransaction; -use SL::DB::Assembly; -use SL::DB::AuditTrail; -use SL::DB::BankAccount; -use SL::DB::Bin; -use SL::DB::Buchungsgruppe; -use SL::DB::Business; -use SL::DB::Chart; -use SL::DB::Contact; -use SL::DB::CustomVariable; -use SL::DB::CustomVariableConfig; -use SL::DB::CustomVariableValidity; -use SL::DB::Customer; -use SL::DB::CustomerTax; -use SL::DB::Datev; -use SL::DB::Default; -use SL::DB::DeliveryOrder; -use SL::DB::DeliveryOrderItem; -use SL::DB::DeliveryOrderItemsStock; -use SL::DB::Department; -use SL::DB::DptTrans; -use SL::DB::Draft; -use SL::DB::Dunning; -use SL::DB::DunningConfig; -use SL::DB::Employee; -use SL::DB::Exchangerate; -use SL::DB::Finanzamt; -use SL::DB::FollowUp; -use SL::DB::FollowUpAccess; -use SL::DB::FollowUpLink; -use SL::DB::GLTransaction; -use SL::DB::GenericTranslation; -use SL::DB::Gifi; -use SL::DB::History; -use SL::DB::Inventory; -use SL::DB::Invoice; -use SL::DB::InvoiceItem; -use SL::DB::Language; -use SL::DB::License; -use SL::DB::LicenseInvoice; -use SL::DB::MakeModel; -use SL::DB::Note; -use SL::DB::Order; -use SL::DB::OrderItem; -use SL::DB::Part; -use SL::DB::PartsGroup; -use SL::DB::PartsTax; -use SL::DB::PaymentTerm; -use SL::DB::PriceFactor; -use SL::DB::Pricegroup; -use SL::DB::Prices; -use SL::DB::Printer; -use SL::DB::Project; -use SL::DB::PurchaseInvoice; -use SL::DB::RMA; -use SL::DB::RMAItem; -use SL::DB::RecordLink; -use SL::DB::SchemaInfo; -use SL::DB::SepaExport; -use SL::DB::SepaExportItem; -use SL::DB::Shipto; -use SL::DB::Status; -use SL::DB::Tax; -use SL::DB::TaxKey; -use SL::DB::TaxZone; -use SL::DB::TodoUserConfig; -use SL::DB::TransferType; -use SL::DB::Translation; -use SL::DB::TranslationPaymentTerm; -use SL::DB::Unit; -use SL::DB::UnitsLanguage; -use SL::DB::Vendor; -use SL::DB::VendorTax; -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 and -having everything loaded. This is supposed to be used only in the -Lx-Office console. Normal modules should C only the modules they -actually need. - -=head1 AUTHOR - -Moritz Bunkus Em.bunkus@linet-services.deE - -=cut diff --git a/SL/DB/Helpers/Attr.pm b/SL/DB/Helpers/Attr.pm deleted file mode 100644 index 01c97c2de..000000000 --- a/SL/DB/Helpers/Attr.pm +++ /dev/null @@ -1,135 +0,0 @@ -package SL::DB::Helper::Attr; - -use strict; - -sub auto_make { - my ($package, %params) = @_; - - for my $col ($package->meta->columns) { - next if $col->primary_key_position; # don't make attr helper for primary keys - _make_by_type($package, $col->name, $col->type); - } - - return $package; -} - -sub make { - my ($package, %params) = @_; - - for my $name (keys %params) { - my @types = ref $params{$name} eq 'ARRAY' ? @{ $params{$name} } : ($params{$name}); - for my $type (@types) { - _make_by_type($package, $name, $type); - } - } - return $package; -} - - - -sub _make_by_type { - my ($package, $name, $type) = @_; - _as_number ($package, $name, places => -2) if $type =~ /numeric | real | float/xi; - _as_percent($package, $name, places => 0) if $type =~ /numeric | real | float/xi; - _as_number ($package, $name, places => 0) if $type =~ /int/xi; - _as_date ($package, $name) if $type =~ /date | timestamp/xi; -} - -sub _as_number { - my $package = shift; - my $attribute = shift; - my %params = @_; - - $params{places} = 2 if !defined($params{places}); - - no strict 'refs'; - *{ $package . '::' . $attribute . '_as_number' } = sub { - my ($self, $string) = @_; - - $self->$attribute($::form->parse_amount(\%::myconfig, $string)) if @_ > 1; - - return $::form->format_amount(\%::myconfig, $self->$attribute, $params{places}); - }; -} - -sub _as_percent { - my $package = shift; - my $attribute = shift; - my %params = @_; - - $params{places} = 2 if !defined($params{places}); - - no strict 'refs'; - *{ $package . '::' . $attribute . '_as_percent' } = sub { - my ($self, $string) = @_; - - $self->$attribute($::form->parse_amount(\%::myconfig, $string) / 100) if @_ > 1; - - return $::form->format_amount(\%::myconfig, 100 * $self->$attribute, $params{places}); - }; - - return 1; -} - -sub _as_date { - my $package = shift; - my $attribute = shift; - my %params = @_; - - no strict 'refs'; - *{ $package . '::' . $attribute . '_as_date' } = sub { - my ($self, $string) = @_; - - if (@_ > 1) { - if ($string) { - my ($yy, $mm, $dd) = $::locale->parse_date(\%::myconfig, $string); - $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 eq 'now' - ? DateTime->now - : $self->$attribute - )->ymd, - $::myconfig{dateformat} - ) - : undef; - }; - - return 1; -} - -1; - - -1; - -__END__ - -=head1 NAME - -SL::DB::Helpers::Attr - attribute helpers - -=head1 SYNOPSIS - - use SL::DB::Helpers::Attr; - SL::DB::Helpers::Attr::make($class, - method_name => 'numeric(15,5)', - datemethod => 'date' - ); - SL::DB::Helpers::Attr::auto_make($class); - -=head1 DESCRIPTION - -=head1 FUNCTIONS - -=head1 BUGS - -=head1 AUTHOR - -=cut diff --git a/SL/DB/Helpers/ConventionManager.pm b/SL/DB/Helpers/ConventionManager.pm deleted file mode 100644 index 1d9cd8415..000000000 --- a/SL/DB/Helpers/ConventionManager.pm +++ /dev/null @@ -1,29 +0,0 @@ -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; diff --git a/SL/DB/Helpers/Manager.pm b/SL/DB/Helpers/Manager.pm deleted file mode 100644 index 4399f5db0..000000000 --- a/SL/DB/Helpers/Manager.pm +++ /dev/null @@ -1,27 +0,0 @@ -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; diff --git a/SL/DB/Helpers/Mappings.pm b/SL/DB/Helpers/Mappings.pm deleted file mode 100644 index 48c486307..000000000 --- a/SL/DB/Helpers/Mappings.pm +++ /dev/null @@ -1,187 +0,0 @@ -package SL::DB::Helpers::Mappings; - -use utf8; -use strict; - -# these will not be managed as Rose::DB models, because they are not normalized, -# significant changes are needed to get them done, or they were done by CRM. -my @lxoffice_blacklist_permanent = qw( - leads -); - -# 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( -); - -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 = ( - acc_trans => 'acc_transaction', - audittrail => 'audit_trail', - ar => 'invoice', - ap => 'purchase_invoice', - bank_accounts => 'bank_account', - buchungsgruppen => 'buchungsgruppe', - contacts => 'contact', - custom_variable_configs => 'custom_variable_config', - custom_variables => 'custom_variable', - custom_variables_validity => 'custom_variable_validity', - customertax => 'customer_tax', - datev => 'datev', - defaults => 'default', - delivery_orders => 'delivery_order', - delivery_order_items => 'delivery_order_item', - department => 'department', - dpt_trans => 'dpt_trans', - drafts => 'draft', - dunning => 'dunning', - dunning_config => 'dunning_config', - employee => 'employee', - exchangerate => 'exchangerate', - finanzamt => 'finanzamt', - follow_up_access => 'follow_up_access', - follow_up_links => 'follow_up_link', - follow_ups => 'follow_up', - generic_translations => 'generic_translation', - gifi => 'gifi', - gl => 'GLTransaction', - history_erp => 'history', - inventory => 'inventory', - invoice => 'invoice_item', - language => 'language', - license => 'license', - licenseinvoice => 'license_invoice', - makemodel => 'make_model', - notes => 'note', - orderitems => 'order_item', - oe => 'order', - parts => 'part', - partsgroup => 'parts_group', - partstax => 'parts_tax', - payment_terms => 'payment_term', - prices => 'prices', - price_factors => 'price_factor', - pricegroup => 'pricegroup', - printers => 'Printer', - record_links => 'record_link', - rma => 'RMA', - rmaitems => 'RMA_item', - sepa_export => 'sepa_export', - sepa_export_items => 'sepa_export_item', - schema_info => 'schema_info', - status => 'status', - tax => 'tax', - taxkeys => 'tax_key', - tax_zones => 'tax_zone', - todo_user_config => 'todo_user_config', - translation => 'translation', - translation_payment_terms => 'translation_payment_term', - units => 'unit', - units_language => 'units_language', - vendortax => 'vendor_tax', -); - -sub get_blacklist { - return LXOFFICE => \@lxoffice_blacklist; -} - -sub get_package_names { - return LXOFFICE => \%lxoffice_package_names; -} - -sub db { - my $string = $_[0]; - my $lookup = $lxoffice_package_names{$_[0]} || - plurify($lxoffice_package_names{singlify($_[0])}); - - for my $thing ($string, $lookup) { - - # best guess? its already the name. like part. camelize it first - my $class = "SL::DB::" . camelify($thing); - return $class if defined *{ $class. '::' }; - - # next, someone wants a manager and pluralized. - my $manager = "SL::DB::Manager::" . singlify(camelify($thing)); - return $manager if defined *{ $manager . '::' }; - } - - die "Can't resolve '$string' as a database model, sorry. Did you perhaps forgot to load it?"; -} - -sub camelify { - my ($str) = @_; - $str =~ s/_+(.)/uc($1)/ge; - ucfirst $str; -} - -sub snakify { - my ($str) = @_; - $str =~ s/(? 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 script. If you add a new table that has -custom mappings, add it here. - -=head2 db - -A special function provided here is E. Without it you'd have to write: - - my $part = SL::DB::Part->new(id => 1234); - my @all_parts = SL::DB::Manager::Part->get_all; - -with them it becomes: - - my $part = db('part')->new(id => 123); - my @all_parts = db('parts')->get_all; - -You don't have to care about add that SL::DB:: incantation anymore. Also, a -simple s at the end will get you the associated Manager class. - -db is written to try to make sense of what you give it, but if all fails, it -will die with an error. - -=head1 BUGS - -nothing yet - -=head1 SEE ALSO - -L - -=head1 AUTHOR - -Sven Schöling - -=cut diff --git a/SL/DB/Helpers/Metadata.pm b/SL/DB/Helpers/Metadata.pm deleted file mode 100644 index e6020a287..000000000 --- a/SL/DB/Helpers/Metadata.pm +++ /dev/null @@ -1,34 +0,0 @@ -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'; -} - -sub initialize { - my $self = shift; - $self->make_attr_auto_helpers unless $self->is_initialized; - $self->SUPER::initialize(@_); -} - -sub make_attr_helpers { - my ($self, %params) = @_; - SL::DB::Helper::Attr::make($self->class, %params); -} - -sub make_attr_auto_helpers { - my ($self) = @_; - SL::DB::Helper::Attr::auto_make($self->class); -} - -1; diff --git a/SL/DB/Manager/DeliveryOrder.pm b/SL/DB/Manager/DeliveryOrder.pm index f63987e88..1b76830ad 100644 --- a/SL/DB/Manager/DeliveryOrder.pm +++ b/SL/DB/Manager/DeliveryOrder.pm @@ -2,8 +2,8 @@ package SL::DB::Manager::DeliveryOrder; use strict; -use SL::DB::Helpers::Manager; -use base qw(SL::DB::Helpers::Manager); +use SL::DB::Helper::Manager; +use base qw(SL::DB::Helper::Manager); sub object_class { 'SL::DB::DeliveryOrder' } diff --git a/SL/DB/Manager/Employee.pm b/SL/DB/Manager/Employee.pm index e52eebb1f..6577c7757 100644 --- a/SL/DB/Manager/Employee.pm +++ b/SL/DB/Manager/Employee.pm @@ -2,8 +2,8 @@ package SL::DB::Manager::Employee; use strict; -use SL::DB::Helpers::Manager; -use base qw(SL::DB::Helpers::Manager); +use SL::DB::Helper::Manager; +use base qw(SL::DB::Helper::Manager); sub object_class { 'SL::DB::Employee' } diff --git a/SL/DB/Manager/Invoice.pm b/SL/DB/Manager/Invoice.pm index 025f7f2d4..c3a9a7bb4 100644 --- a/SL/DB/Manager/Invoice.pm +++ b/SL/DB/Manager/Invoice.pm @@ -2,7 +2,7 @@ package SL::DB::Manager::Invoice; use strict; -use base qw(SL::DB::Helpers::Manager); +use base qw(SL::DB::Helper::Manager); sub object_class { 'SL::DB::Invoice' } diff --git a/SL/DB/Manager/Order.pm b/SL/DB/Manager/Order.pm index 451a43aaf..fc2b796ba 100644 --- a/SL/DB/Manager/Order.pm +++ b/SL/DB/Manager/Order.pm @@ -2,8 +2,8 @@ package SL::DB::Manager::Order; use strict; -use SL::DB::Helpers::Manager; -use base qw(SL::DB::Helpers::Manager); +use SL::DB::Helper::Manager; +use base qw(SL::DB::Helper::Manager); sub object_class { 'SL::DB::Order' } diff --git a/SL/DB/Manager/Part.pm b/SL/DB/Manager/Part.pm index 1564b9b79..e6aca1f71 100644 --- a/SL/DB/Manager/Part.pm +++ b/SL/DB/Manager/Part.pm @@ -2,8 +2,8 @@ package SL::DB::Manager::Part; use strict; -use SL::DB::Helpers::Manager; -use base qw(SL::DB::Helpers::Manager); +use SL::DB::Helper::Manager; +use base qw(SL::DB::Helper::Manager); use Carp; use SL::DBUtils; diff --git a/SL/DB/Manager/PurchaseInvoice.pm b/SL/DB/Manager/PurchaseInvoice.pm index c717a047f..1cc573795 100644 --- a/SL/DB/Manager/PurchaseInvoice.pm +++ b/SL/DB/Manager/PurchaseInvoice.pm @@ -2,8 +2,8 @@ package SL::DB::Manager::PurchaseInvoice; use strict; -use SL::DB::Helpers::Manager; -use base qw(SL::DB::Helpers::Manager); +use SL::DB::Helper::Manager; +use base qw(SL::DB::Helper::Manager); sub object_class { 'SL::DB::PurchaseInvoice' } diff --git a/SL/DB/Manager/TransferType.pm b/SL/DB/Manager/TransferType.pm index 82bcc5fa1..2b4f1e6c0 100644 --- a/SL/DB/Manager/TransferType.pm +++ b/SL/DB/Manager/TransferType.pm @@ -2,7 +2,7 @@ package SL::DB::Manager::TransferType; use strict; -use base qw(SL::DB::Helpers::Manager); +use base qw(SL::DB::Helper::Manager); use Carp; diff --git a/SL/DB/Object.pm b/SL/DB/Object.pm index 52b9300a9..0a698268c 100644 --- a/SL/DB/Object.pm +++ b/SL/DB/Object.pm @@ -7,9 +7,9 @@ use Rose::DB::Object; use List::MoreUtils qw(any); use SL::DB; -use SL::DB::Helpers::Attr; -use SL::DB::Helpers::Metadata; -use SL::DB::Helpers::Manager; +use SL::DB::Helper::Attr; +use SL::DB::Helper::Metadata; +use SL::DB::Helper::Manager; use base qw(Rose::DB::Object); @@ -31,7 +31,7 @@ sub init_db { } sub meta_class { - return 'SL::DB::Helpers::Metadata'; + return 'SL::DB::Helper::Metadata'; } sub _get_manager_class { @@ -61,9 +61,10 @@ sub _assign_attributes { 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); + $value = $type eq 'boolean' ? ($value ? 't' : 'f') + : $text_column_types{$type} ? $value + : defined($value) && ($value eq '') ? undef + : $value; $self->$attribute($value); } diff --git a/bin/mozilla/common.pl b/bin/mozilla/common.pl index 143551f74..a6f7ef48c 100644 --- a/bin/mozilla/common.pl +++ b/bin/mozilla/common.pl @@ -730,9 +730,9 @@ sub gl_transaction { if ($::use_rdbo) { eval { - require SL::DB::Helpers::Mappings; + require SL::DB::Helper::Mappings; sub db { - goto &SL::DB::Helpers::Mappings::db; + goto &SL::DB::Helper::Mappings::db; } } or die $@; } diff --git a/scripts/rose_auto_create_model.pl b/scripts/rose_auto_create_model.pl index b1a704089..f222cfa97 100755 --- a/scripts/rose_auto_create_model.pl +++ b/scripts/rose_auto_create_model.pl @@ -18,8 +18,8 @@ use SL::DB; use SL::Form; use SL::Locale; use SL::LXDebug; -use SL::DB::Helpers::ALL; -use SL::DB::Helpers::Mappings; +use SL::DB::Helper::ALL; +use SL::DB::Helper::Mappings; our $form; our $cgi; @@ -131,8 +131,8 @@ CODE setup(); -my %blacklist = SL::DB::Helpers::Mappings->get_blacklist; -my %package_names = SL::DB::Helpers::Mappings->get_package_names; +my %blacklist = SL::DB::Helper::Mappings->get_blacklist; +my %package_names = SL::DB::Helper::Mappings->get_package_names; my @tables = (); if (($ARGV[0] eq '--all') || ($ARGV[0] eq '-a') || ($ARGV[0] eq '--sugar') || ($ARGV[0] eq '-s')) { diff --git a/t/helper/mapping.t b/t/helper/mapping.t index d0c015cf6..96a8f038d 100644 --- a/t/helper/mapping.t +++ b/t/helper/mapping.t @@ -1,7 +1,7 @@ use Test::More tests => 12; -use_ok 'SL::DB::Helpers::ALL'; -use_ok 'SL::DB::Helpers::Mappings', qw(db); +use_ok 'SL::DB::Helper::ALL'; +use_ok 'SL::DB::Helper::Mappings', qw(db); is db('part'), 'SL::DB::Part'; is db('parts'), 'SL::DB::Manager::Part';