Revision ac552280
Von Moritz Bunkus vor fast 14 Jahren hinzugefügt
SL/DB/Helper/ALL.pm | ||
---|---|---|
1 |
package SL::DB::Helper::ALL; |
|
2 |
|
|
3 |
use strict; |
|
4 |
|
|
5 |
use SL::DB::AccTrans; |
|
6 |
use SL::DB::AccTransaction; |
|
7 |
use SL::DB::Assembly; |
|
8 |
use SL::DB::AuditTrail; |
|
9 |
use SL::DB::BankAccount; |
|
10 |
use SL::DB::Bin; |
|
11 |
use SL::DB::Buchungsgruppe; |
|
12 |
use SL::DB::Business; |
|
13 |
use SL::DB::Chart; |
|
14 |
use SL::DB::Contact; |
|
15 |
use SL::DB::CustomVariable; |
|
16 |
use SL::DB::CustomVariableConfig; |
|
17 |
use SL::DB::CustomVariableValidity; |
|
18 |
use SL::DB::Customer; |
|
19 |
use SL::DB::CustomerTax; |
|
20 |
use SL::DB::Datev; |
|
21 |
use SL::DB::Default; |
|
22 |
use SL::DB::DeliveryOrder; |
|
23 |
use SL::DB::DeliveryOrderItem; |
|
24 |
use SL::DB::DeliveryOrderItemsStock; |
|
25 |
use SL::DB::Department; |
|
26 |
use SL::DB::DptTrans; |
|
27 |
use SL::DB::Draft; |
|
28 |
use SL::DB::Dunning; |
|
29 |
use SL::DB::DunningConfig; |
|
30 |
use SL::DB::Employee; |
|
31 |
use SL::DB::Exchangerate; |
|
32 |
use SL::DB::Finanzamt; |
|
33 |
use SL::DB::FollowUp; |
|
34 |
use SL::DB::FollowUpAccess; |
|
35 |
use SL::DB::FollowUpLink; |
|
36 |
use SL::DB::GLTransaction; |
|
37 |
use SL::DB::GenericTranslation; |
|
38 |
use SL::DB::Gifi; |
|
39 |
use SL::DB::History; |
|
40 |
use SL::DB::Inventory; |
|
41 |
use SL::DB::Invoice; |
|
42 |
use SL::DB::InvoiceItem; |
|
43 |
use SL::DB::Language; |
|
44 |
use SL::DB::License; |
|
45 |
use SL::DB::LicenseInvoice; |
|
46 |
use SL::DB::MakeModel; |
|
47 |
use SL::DB::Note; |
|
48 |
use SL::DB::Order; |
|
49 |
use SL::DB::OrderItem; |
|
50 |
use SL::DB::Part; |
|
51 |
use SL::DB::PartsGroup; |
|
52 |
use SL::DB::PartsTax; |
|
53 |
use SL::DB::PaymentTerm; |
|
54 |
use SL::DB::PriceFactor; |
|
55 |
use SL::DB::Pricegroup; |
|
56 |
use SL::DB::Prices; |
|
57 |
use SL::DB::Printer; |
|
58 |
use SL::DB::Project; |
|
59 |
use SL::DB::PurchaseInvoice; |
|
60 |
use SL::DB::RMA; |
|
61 |
use SL::DB::RMAItem; |
|
62 |
use SL::DB::RecordLink; |
|
63 |
use SL::DB::SchemaInfo; |
|
64 |
use SL::DB::SepaExport; |
|
65 |
use SL::DB::SepaExportItem; |
|
66 |
use SL::DB::Shipto; |
|
67 |
use SL::DB::Status; |
|
68 |
use SL::DB::Tax; |
|
69 |
use SL::DB::TaxKey; |
|
70 |
use SL::DB::TaxZone; |
|
71 |
use SL::DB::TodoUserConfig; |
|
72 |
use SL::DB::TransferType; |
|
73 |
use SL::DB::Translation; |
|
74 |
use SL::DB::TranslationPaymentTerm; |
|
75 |
use SL::DB::Unit; |
|
76 |
use SL::DB::UnitsLanguage; |
|
77 |
use SL::DB::Vendor; |
|
78 |
use SL::DB::VendorTax; |
|
79 |
use SL::DB::Warehouse; |
|
80 |
|
|
81 |
1; |
|
82 |
|
|
83 |
__END__ |
|
84 |
|
|
85 |
=pod |
|
86 |
|
|
87 |
=head1 NAME |
|
88 |
|
|
89 |
SL::DB::Helper::ALL: Dependency-only package for all SL::DB::* modules |
|
90 |
|
|
91 |
=head1 SYNOPSIS |
|
92 |
|
|
93 |
use SL::DB::Helper::ALL; |
|
94 |
|
|
95 |
=head1 DESCRIPTION |
|
96 |
|
|
97 |
This module depends on all modules in SL/DB/*.pm for the convenience |
|
98 |
of being able to write a simple \C<use SL::DB::Helper::ALL> and |
|
99 |
having everything loaded. This is supposed to be used only in the |
|
100 |
Lx-Office console. Normal modules should C<use> only the modules they |
|
101 |
actually need. |
|
102 |
|
|
103 |
=head1 AUTHOR |
|
104 |
|
|
105 |
Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt> |
|
106 |
|
|
107 |
=cut |
SL/DB/Helper/Attr.pm | ||
---|---|---|
1 |
package SL::DB::Helper::Attr; |
|
2 |
|
|
3 |
use strict; |
|
4 |
|
|
5 |
sub auto_make { |
|
6 |
my ($package, %params) = @_; |
|
7 |
|
|
8 |
for my $col ($package->meta->columns) { |
|
9 |
next if $col->primary_key_position; # don't make attr helper for primary keys |
|
10 |
_make_by_type($package, $col->name, $col->type); |
|
11 |
} |
|
12 |
|
|
13 |
return $package; |
|
14 |
} |
|
15 |
|
|
16 |
sub make { |
|
17 |
my ($package, %params) = @_; |
|
18 |
|
|
19 |
for my $name (keys %params) { |
|
20 |
my @types = ref $params{$name} eq 'ARRAY' ? @{ $params{$name} } : ($params{$name}); |
|
21 |
for my $type (@types) { |
|
22 |
_make_by_type($package, $name, $type); |
|
23 |
} |
|
24 |
} |
|
25 |
return $package; |
|
26 |
} |
|
27 |
|
|
28 |
|
|
29 |
|
|
30 |
sub _make_by_type { |
|
31 |
my ($package, $name, $type) = @_; |
|
32 |
_as_number ($package, $name, places => -2) if $type =~ /numeric | real | float/xi; |
|
33 |
_as_percent($package, $name, places => 0) if $type =~ /numeric | real | float/xi; |
|
34 |
_as_number ($package, $name, places => 0) if $type =~ /int/xi; |
|
35 |
_as_date ($package, $name) if $type =~ /date | timestamp/xi; |
|
36 |
} |
|
37 |
|
|
38 |
sub _as_number { |
|
39 |
my $package = shift; |
|
40 |
my $attribute = shift; |
|
41 |
my %params = @_; |
|
42 |
|
|
43 |
$params{places} = 2 if !defined($params{places}); |
|
44 |
|
|
45 |
no strict 'refs'; |
|
46 |
*{ $package . '::' . $attribute . '_as_number' } = sub { |
|
47 |
my ($self, $string) = @_; |
|
48 |
|
|
49 |
$self->$attribute($::form->parse_amount(\%::myconfig, $string)) if @_ > 1; |
|
50 |
|
|
51 |
return $::form->format_amount(\%::myconfig, $self->$attribute, $params{places}); |
|
52 |
}; |
|
53 |
} |
|
54 |
|
|
55 |
sub _as_percent { |
|
56 |
my $package = shift; |
|
57 |
my $attribute = shift; |
|
58 |
my %params = @_; |
|
59 |
|
|
60 |
$params{places} = 2 if !defined($params{places}); |
|
61 |
|
|
62 |
no strict 'refs'; |
|
63 |
*{ $package . '::' . $attribute . '_as_percent' } = sub { |
|
64 |
my ($self, $string) = @_; |
|
65 |
|
|
66 |
$self->$attribute($::form->parse_amount(\%::myconfig, $string) / 100) if @_ > 1; |
|
67 |
|
|
68 |
return $::form->format_amount(\%::myconfig, 100 * $self->$attribute, $params{places}); |
|
69 |
}; |
|
70 |
|
|
71 |
return 1; |
|
72 |
} |
|
73 |
|
|
74 |
sub _as_date { |
|
75 |
my $package = shift; |
|
76 |
my $attribute = shift; |
|
77 |
my %params = @_; |
|
78 |
|
|
79 |
no strict 'refs'; |
|
80 |
*{ $package . '::' . $attribute . '_as_date' } = sub { |
|
81 |
my ($self, $string) = @_; |
|
82 |
|
|
83 |
if (@_ > 1) { |
|
84 |
if ($string) { |
|
85 |
my ($yy, $mm, $dd) = $::locale->parse_date(\%::myconfig, $string); |
|
86 |
$self->$attribute(DateTime->new(year => $yy, month => $mm, day => $dd)); |
|
87 |
} else { |
|
88 |
$self->$attribute(undef); |
|
89 |
} |
|
90 |
} |
|
91 |
|
|
92 |
return $self->$attribute |
|
93 |
? $::locale->reformat_date( |
|
94 |
{ dateformat => 'yy-mm-dd' }, |
|
95 |
( $self->$attribute eq 'now' |
|
96 |
? DateTime->now |
|
97 |
: $self->$attribute |
|
98 |
)->ymd, |
|
99 |
$::myconfig{dateformat} |
|
100 |
) |
|
101 |
: undef; |
|
102 |
}; |
|
103 |
|
|
104 |
return 1; |
|
105 |
} |
|
106 |
|
|
107 |
1; |
|
108 |
|
|
109 |
|
|
110 |
1; |
|
111 |
|
|
112 |
__END__ |
|
113 |
|
|
114 |
=head1 NAME |
|
115 |
|
|
116 |
SL::DB::Helper::Attr - attribute helpers |
|
117 |
|
|
118 |
=head1 SYNOPSIS |
|
119 |
|
|
120 |
use SL::DB::Helper::Attr; |
|
121 |
SL::DB::Helper::Attr::make($class, |
|
122 |
method_name => 'numeric(15,5)', |
|
123 |
datemethod => 'date' |
|
124 |
); |
|
125 |
SL::DB::Helper::Attr::auto_make($class); |
|
126 |
|
|
127 |
=head1 DESCRIPTION |
|
128 |
|
|
129 |
=head1 FUNCTIONS |
|
130 |
|
|
131 |
=head1 BUGS |
|
132 |
|
|
133 |
=head1 AUTHOR |
|
134 |
|
|
135 |
=cut |
SL/DB/Helper/ConventionManager.pm | ||
---|---|---|
1 |
package SL::DB::Helper::ConventionManager; |
|
2 |
|
|
3 |
use strict; |
|
4 |
|
|
5 |
use Rose::DB::Object::ConventionManager; |
|
6 |
|
|
7 |
use base qw(Rose::DB::Object::ConventionManager); |
|
8 |
|
|
9 |
sub auto_manager_class_name { |
|
10 |
my $self = shift; |
|
11 |
my $object_class = shift || $self->meta->class; |
|
12 |
|
|
13 |
my @parts = split m/::/, $object_class; |
|
14 |
my $last = pop @parts; |
|
15 |
|
|
16 |
return join('::', @parts, 'Manager', $last); |
|
17 |
} |
|
18 |
|
|
19 |
# Base name used for 'make_manager_class', e.g. 'get_all', |
|
20 |
# 'update_all' |
|
21 |
sub auto_manager_base_name { |
|
22 |
return 'all'; |
|
23 |
} |
|
24 |
|
|
25 |
sub auto_manager_base_class { |
|
26 |
return 'SL::DB::Helper::Manager'; |
|
27 |
} |
|
28 |
|
|
29 |
1; |
SL/DB/Helper/Manager.pm | ||
---|---|---|
1 |
package SL::DB::Helper::Manager; |
|
2 |
|
|
3 |
use strict; |
|
4 |
|
|
5 |
use Rose::DB::Object::Manager; |
|
6 |
use base qw(Rose::DB::Object::Manager); |
|
7 |
|
|
8 |
sub make_manager_methods { |
|
9 |
my $class = shift; |
|
10 |
my @params = scalar(@_) ? @_ : qw(all); |
|
11 |
return $class->SUPER::make_manager_methods(@params); |
|
12 |
} |
|
13 |
|
|
14 |
sub find_by { |
|
15 |
my $class = shift; |
|
16 |
|
|
17 |
return if !@_; |
|
18 |
return $class->get_all(query => [ @_ ], limit => 1)->[0]; |
|
19 |
} |
|
20 |
|
|
21 |
sub get_first { |
|
22 |
shift->get_all( |
|
23 |
limit => 1, |
|
24 |
)->[0]; |
|
25 |
} |
|
26 |
|
|
27 |
1; |
SL/DB/Helper/Mappings.pm | ||
---|---|---|
1 |
package SL::DB::Helpers::Mappings; |
|
2 |
|
|
3 |
use utf8; |
|
4 |
use strict; |
|
5 |
|
|
6 |
# these will not be managed as Rose::DB models, because they are not normalized, |
|
7 |
# significant changes are needed to get them done, or they were done by CRM. |
|
8 |
my @lxoffice_blacklist_permanent = qw( |
|
9 |
leads |
|
10 |
); |
|
11 |
|
|
12 |
# these are not managed _yet_, but will hopefully at some point. |
|
13 |
# if you are confident that one of these works, remove it here. |
|
14 |
my @lxoffice_blacklist_temp = qw( |
|
15 |
); |
|
16 |
|
|
17 |
my @lxoffice_blacklist = (@lxoffice_blacklist_permanent, @lxoffice_blacklist_temp); |
|
18 |
|
|
19 |
# map table names to their models. |
|
20 |
# unlike rails we have no singular<->plural magic. |
|
21 |
# remeber: tables should be named as the plural of the model name. |
|
22 |
my %lxoffice_package_names = ( |
|
23 |
acc_trans => 'acc_transaction', |
|
24 |
audittrail => 'audit_trail', |
|
25 |
ar => 'invoice', |
|
26 |
ap => 'purchase_invoice', |
|
27 |
bank_accounts => 'bank_account', |
|
28 |
buchungsgruppen => 'buchungsgruppe', |
|
29 |
contacts => 'contact', |
|
30 |
custom_variable_configs => 'custom_variable_config', |
|
31 |
custom_variables => 'custom_variable', |
|
32 |
custom_variables_validity => 'custom_variable_validity', |
|
33 |
customertax => 'customer_tax', |
|
34 |
datev => 'datev', |
|
35 |
defaults => 'default', |
|
36 |
delivery_orders => 'delivery_order', |
|
37 |
delivery_order_items => 'delivery_order_item', |
|
38 |
department => 'department', |
|
39 |
dpt_trans => 'dpt_trans', |
|
40 |
drafts => 'draft', |
|
41 |
dunning => 'dunning', |
|
42 |
dunning_config => 'dunning_config', |
|
43 |
employee => 'employee', |
|
44 |
exchangerate => 'exchangerate', |
|
45 |
finanzamt => 'finanzamt', |
|
46 |
follow_up_access => 'follow_up_access', |
|
47 |
follow_up_links => 'follow_up_link', |
|
48 |
follow_ups => 'follow_up', |
|
49 |
generic_translations => 'generic_translation', |
|
50 |
gifi => 'gifi', |
|
51 |
gl => 'GLTransaction', |
|
52 |
history_erp => 'history', |
|
53 |
inventory => 'inventory', |
|
54 |
invoice => 'invoice_item', |
|
55 |
language => 'language', |
|
56 |
license => 'license', |
|
57 |
licenseinvoice => 'license_invoice', |
|
58 |
makemodel => 'make_model', |
|
59 |
notes => 'note', |
|
60 |
orderitems => 'order_item', |
|
61 |
oe => 'order', |
|
62 |
parts => 'part', |
|
63 |
partsgroup => 'parts_group', |
|
64 |
partstax => 'parts_tax', |
|
65 |
payment_terms => 'payment_term', |
|
66 |
prices => 'prices', |
|
67 |
price_factors => 'price_factor', |
|
68 |
pricegroup => 'pricegroup', |
|
69 |
printers => 'Printer', |
|
70 |
record_links => 'record_link', |
|
71 |
rma => 'RMA', |
|
72 |
rmaitems => 'RMA_item', |
|
73 |
sepa_export => 'sepa_export', |
|
74 |
sepa_export_items => 'sepa_export_item', |
|
75 |
schema_info => 'schema_info', |
|
76 |
status => 'status', |
|
77 |
tax => 'tax', |
|
78 |
taxkeys => 'tax_key', |
|
79 |
tax_zones => 'tax_zone', |
|
80 |
todo_user_config => 'todo_user_config', |
|
81 |
translation => 'translation', |
|
82 |
translation_payment_terms => 'translation_payment_term', |
|
83 |
units => 'unit', |
|
84 |
units_language => 'units_language', |
|
85 |
vendortax => 'vendor_tax', |
|
86 |
); |
|
87 |
|
|
88 |
sub get_blacklist { |
|
89 |
return LXOFFICE => \@lxoffice_blacklist; |
|
90 |
} |
|
91 |
|
|
92 |
sub get_package_names { |
|
93 |
return LXOFFICE => \%lxoffice_package_names; |
|
94 |
} |
|
95 |
|
|
96 |
sub db { |
|
97 |
my $string = $_[0]; |
|
98 |
my $lookup = $lxoffice_package_names{$_[0]} || |
|
99 |
plurify($lxoffice_package_names{singlify($_[0])}); |
|
100 |
|
|
101 |
for my $thing ($string, $lookup) { |
|
102 |
|
|
103 |
# best guess? its already the name. like part. camelize it first |
|
104 |
my $class = "SL::DB::" . camelify($thing); |
|
105 |
return $class if defined *{ $class. '::' }; |
|
106 |
|
|
107 |
# next, someone wants a manager and pluralized. |
|
108 |
my $manager = "SL::DB::Manager::" . singlify(camelify($thing)); |
|
109 |
return $manager if defined *{ $manager . '::' }; |
|
110 |
} |
|
111 |
|
|
112 |
die "Can't resolve '$string' as a database model, sorry. Did you perhaps forgot to load it?"; |
|
113 |
} |
|
114 |
|
|
115 |
sub camelify { |
|
116 |
my ($str) = @_; |
|
117 |
$str =~ s/_+(.)/uc($1)/ge; |
|
118 |
ucfirst $str; |
|
119 |
} |
|
120 |
|
|
121 |
sub snakify { |
|
122 |
my ($str) = @_; |
|
123 |
$str =~ s/(?<!^)\u(.)/'_' . lc($1)/ge; |
|
124 |
lcfirst $str; |
|
125 |
} |
|
126 |
|
|
127 |
sub plurify { |
|
128 |
my ($str) = @_; |
|
129 |
$str . 's'; |
|
130 |
} |
|
131 |
|
|
132 |
sub singlify { |
|
133 |
my ($str) = @_; |
|
134 |
local $/ = 's'; |
|
135 |
chomp $str; |
|
136 |
$str; |
|
137 |
} |
|
138 |
|
|
139 |
1; |
|
140 |
|
|
141 |
__END__ |
|
142 |
|
|
143 |
=head1 NAME |
|
144 |
|
|
145 |
SL::DB::Helpers::Mappings - Rose Table <-> Model mapping information |
|
146 |
|
|
147 |
=head1 SYNOPSIS |
|
148 |
|
|
149 |
use SL::DB::Helpers::Mappings qw(@blacklist %table2model); |
|
150 |
|
|
151 |
=head1 DESCRIPTION |
|
152 |
|
|
153 |
This modul stores table <-> model mappings used by the |
|
154 |
L<scripts/rose_auto_create_model.pl> script. If you add a new table that has |
|
155 |
custom mappings, add it here. |
|
156 |
|
|
157 |
=head2 db |
|
158 |
|
|
159 |
A special function provided here is E<db>. Without it you'd have to write: |
|
160 |
|
|
161 |
my $part = SL::DB::Part->new(id => 1234); |
|
162 |
my @all_parts = SL::DB::Manager::Part->get_all; |
|
163 |
|
|
164 |
with them it becomes: |
|
165 |
|
|
166 |
my $part = db('part')->new(id => 123); |
|
167 |
my @all_parts = db('parts')->get_all; |
|
168 |
|
|
169 |
You don't have to care about add that SL::DB:: incantation anymore. Also, a |
|
170 |
simple s at the end will get you the associated Manager class. |
|
171 |
|
|
172 |
db is written to try to make sense of what you give it, but if all fails, it |
|
173 |
will die with an error. |
|
174 |
|
|
175 |
=head1 BUGS |
|
176 |
|
|
177 |
nothing yet |
|
178 |
|
|
179 |
=head1 SEE ALSO |
|
180 |
|
|
181 |
L<scripts/rose_auto_create_model.pl> |
|
182 |
|
|
183 |
=head1 AUTHOR |
|
184 |
|
|
185 |
Sven Schöling <s.schoeling@linet-services.de> |
|
186 |
|
|
187 |
=cut |
SL/DB/Helper/Metadata.pm | ||
---|---|---|
1 |
package SL::DB::Helper::Metadata; |
|
2 |
|
|
3 |
use strict; |
|
4 |
|
|
5 |
use Rose::DB::Object::Metadata; |
|
6 |
use SL::DB::Helper::ConventionManager; |
|
7 |
|
|
8 |
use base qw(Rose::DB::Object::Metadata); |
|
9 |
|
|
10 |
sub convention_manager_class { |
|
11 |
return 'SL::DB::Helper::ConventionManager'; |
|
12 |
} |
|
13 |
|
|
14 |
sub default_manager_base_class { |
|
15 |
return 'SL::DB::Helper::Manager'; |
|
16 |
} |
|
17 |
|
|
18 |
sub initialize { |
|
19 |
my $self = shift; |
|
20 |
$self->make_attr_auto_helpers unless $self->is_initialized; |
|
21 |
$self->SUPER::initialize(@_); |
|
22 |
} |
|
23 |
|
|
24 |
sub make_attr_helpers { |
|
25 |
my ($self, %params) = @_; |
|
26 |
SL::DB::Helper::Attr::make($self->class, %params); |
|
27 |
} |
|
28 |
|
|
29 |
sub make_attr_auto_helpers { |
|
30 |
my ($self) = @_; |
|
31 |
SL::DB::Helper::Attr::auto_make($self->class); |
|
32 |
} |
|
33 |
|
|
34 |
1; |
SL/DB/Helper/Sorted.pm | ||
---|---|---|
1 |
package SL::DB::Helper::Sorted; |
|
2 |
|
|
3 |
use strict; |
|
4 |
|
|
5 |
require Exporter; |
|
6 |
our @ISA = qw(Exporter); |
|
7 |
our @EXPORT = qw(get_all_sorted make_sort_string); |
|
8 |
|
|
9 |
my %sort_spec; |
|
10 |
|
|
11 |
sub make_sort_string { |
|
12 |
my ($class, %params) = @_; |
|
13 |
|
|
14 |
my $sort_spec = _get_sort_spec($class); |
|
15 |
|
|
16 |
my $sort_dir = defined($params{sort_dir}) ? $params{sort_dir} * 1 : $sort_spec->{default}->[1]; |
|
17 |
my $sort_dir_str = $sort_dir ? 'ASC' : 'DESC'; |
|
18 |
|
|
19 |
my $sort_by = $params{sort_by}; |
|
20 |
$sort_by = $sort_spec->{default}->[0] unless $sort_spec->{columns}->{$sort_by}; |
|
21 |
|
|
22 |
my $nulls_str = ''; |
|
23 |
if ($sort_spec->{nulls}) { |
|
24 |
$nulls_str = ref($sort_spec->{nulls}) ? ($sort_spec->{nulls}->{$sort_by} || $sort_spec->{nulls}->{default}) : $sort_spec->{nulls}; |
|
25 |
$nulls_str = " NULLS ${nulls_str}" if $nulls_str; |
|
26 |
} |
|
27 |
|
|
28 |
my $sort_by_str = $sort_spec->{columns}->{$sort_by}; |
|
29 |
$sort_by_str = [ $sort_by_str ] unless ref($sort_by_str) eq 'ARRAY'; |
|
30 |
$sort_by_str = join(', ', map { "${_} ${sort_dir_str}${nulls_str}" } @{ $sort_by_str }); |
|
31 |
|
|
32 |
return wantarray ? ($sort_by, $sort_dir, $sort_by_str) : $sort_by_str; |
|
33 |
} |
|
34 |
|
|
35 |
sub get_all_sorted { |
|
36 |
my ($class, %params) = @_; |
|
37 |
my $sort_str = $class->make_sort_string(sort_by => delete($params{sort_by}), sort_dir => delete($params{sort_dir})); |
|
38 |
|
|
39 |
return $class->get_all(sort_by => $sort_str, %params); |
|
40 |
} |
|
41 |
|
|
42 |
sub _get_sort_spec { |
|
43 |
my ($class) = @_; |
|
44 |
return $sort_spec{$class} ||= _make_sort_spec($class); |
|
45 |
} |
|
46 |
|
|
47 |
sub _make_sort_spec { |
|
48 |
my ($class) = @_; |
|
49 |
|
|
50 |
my %sort_spec = $class->_sort_spec if defined &{ "${class}::_sort_spec" }; |
|
51 |
|
|
52 |
my $meta = $class->object_class->meta; |
|
53 |
|
|
54 |
if (!$sort_spec{default}) { |
|
55 |
my @primary_keys = $meta->primary_key; |
|
56 |
$sort_spec{default} = [ "" . $primary_keys[0], 1 ]; |
|
57 |
} |
|
58 |
|
|
59 |
$sort_spec{columns} ||= { SIMPLE => [ map { "$_" } $meta->columns ] }; |
|
60 |
|
|
61 |
if ($sort_spec{columns}->{SIMPLE}) { |
|
62 |
my $table = $meta->table; |
|
63 |
|
|
64 |
if (!ref($sort_spec{columns}->{SIMPLE}) && ($sort_spec{columns}->{SIMPLE} eq 'ALL')) { |
|
65 |
map { $sort_spec{columns}->{"$_"} ||= "${table}.${_}"} @{ $meta->columns }; |
|
66 |
delete $sort_spec{columns}->{SIMPLE}; |
|
67 |
} else { |
|
68 |
map { $sort_spec{columns}->{$_} = "${table}.${_}" } @{ delete($sort_spec{columns}->{SIMPLE}) }; |
|
69 |
} |
|
70 |
} |
|
71 |
|
|
72 |
return \%sort_spec; |
|
73 |
} |
|
74 |
|
|
75 |
1; |
|
76 |
|
|
77 |
__END__ |
|
78 |
|
|
79 |
=encoding utf8 |
|
80 |
|
|
81 |
=head1 NAME |
|
82 |
|
|
83 |
SL::DB::Helper::Sorted - Mixin for a manager class that handles |
|
84 |
sorting of database records |
|
85 |
|
|
86 |
=head1 SYNOPSIS |
|
87 |
|
|
88 |
package SL::DB::Manager::Message; |
|
89 |
|
|
90 |
use SL::DB::Helper::Sorted; |
|
91 |
|
|
92 |
sub _sort_spec { |
|
93 |
return ( columns => { recipient_id => [ 'CASE |
|
94 |
WHEN recipient_group_id IS NULL THEN lower(recipient.name) |
|
95 |
ELSE lower(recipient_group.name) |
|
96 |
END', ], |
|
97 |
sender_id => [ 'lower(sender.name)', ], |
|
98 |
created_at => [ 'created_at', ], |
|
99 |
subject => [ 'lower(subject)', ], |
|
100 |
status => [ 'NOT COALESCE(unread, FALSE)', 'created_at' ], |
|
101 |
}, |
|
102 |
default => [ 'status', 1 ], |
|
103 |
nulls => { default => 'LAST', |
|
104 |
subject => 'FIRST', |
|
105 |
} |
|
106 |
); |
|
107 |
} |
|
108 |
|
|
109 |
package SL::Controller::Message; |
|
110 |
|
|
111 |
sub action_list { |
|
112 |
my $messages = SL::DB::Manager::Message->get_all_sorted(sort_by => $::form->{sort_by}, |
|
113 |
sort_dir => $::form->{sort_dir}); |
|
114 |
} |
|
115 |
|
|
116 |
=head1 CLASS FUNCTIONS |
|
117 |
|
|
118 |
=over 4 |
|
119 |
|
|
120 |
=item C<make_sort_string %params> |
|
121 |
|
|
122 |
Evaluates C<$params{sort_by}> and C<$params{sort_dir}> and returns an |
|
123 |
SQL string suitable for sorting. The package this package is mixed |
|
124 |
into has to provide a method L</_sort_spec> that returns a hash whose |
|
125 |
structure is explained below. That hash is authoritive in which |
|
126 |
columns may be sorted, which column to sort by by default and how to |
|
127 |
handle C<NULL> values. |
|
128 |
|
|
129 |
Returns the SQL string in scalar context. In array context it returns |
|
130 |
three values: the actual column it sorts by (suitable for another call |
|
131 |
to L</make_sort_string>), the actual sort direction (either 0 or 1) |
|
132 |
and the SQL string. |
|
133 |
|
|
134 |
=item C<get_all_sorted %params> |
|
135 |
|
|
136 |
Returns C<< $class->get_all >> with C<sort_by> set to the value |
|
137 |
returned by c<< $class->make_sort_string(%params) >>. |
|
138 |
|
|
139 |
=back |
|
140 |
|
|
141 |
=head1 CLASS FUNCTIONS PROVIDED BY THE MIXING PACKAGE |
|
142 |
|
|
143 |
=over 4 |
|
144 |
|
|
145 |
=item C<_sort_spec> |
|
146 |
|
|
147 |
This method is actually not part of this package but can be provided |
|
148 |
by the package this helper is mixed into. If it isn't then all columns |
|
149 |
of the corresponding table (as returned by the model's meta data) will |
|
150 |
be eligible for sorting. |
|
151 |
|
|
152 |
Returns a hash with the following keys: |
|
153 |
|
|
154 |
=over 2 |
|
155 |
|
|
156 |
=item C<default> |
|
157 |
|
|
158 |
A two-element array containing the name and direction by which to sort |
|
159 |
in default cases. Example: |
|
160 |
|
|
161 |
default => [ 'name', 1 ], |
|
162 |
|
|
163 |
Defaults to the table's primary key column (the first column if the |
|
164 |
primary key is composited). |
|
165 |
|
|
166 |
=item C<columns> |
|
167 |
|
|
168 |
A hash reference. Its keys are column names, and its values are SQL |
|
169 |
strings by which to sort. Example: |
|
170 |
|
|
171 |
columns => { SIMPLE => [ 'transaction_description', 'orddate' ], |
|
172 |
the_date => 'CASE WHEN oe.quotation THEN oe.quodate ELSE oe.orddate END', |
|
173 |
customer_name => 'lower(customer.name)', |
|
174 |
}, |
|
175 |
|
|
176 |
If sorting by a column is requested that is not a key in this hash |
|
177 |
then the default column name will be used. |
|
178 |
|
|
179 |
The value can be either a scalar or an array reference. If it's the |
|
180 |
latter then both the sort direction as well as the null handling will |
|
181 |
be appended to each of its members. |
|
182 |
|
|
183 |
The special key C<SIMPLE> can be a scalar or an array reference. If it |
|
184 |
is an array reference then it contains column names that are mapped |
|
185 |
1:1 onto the table's columns. If it is the scalar 'ALL' then all |
|
186 |
columns in that model's meta data are mapped 1:1 unless the C<columns> |
|
187 |
hash already contains a key for that column. |
|
188 |
|
|
189 |
If C<columns> is missing then all columns of the model will be |
|
190 |
eligible for sorting. The list of columns is looked up in the model's |
|
191 |
meta data. |
|
192 |
|
|
193 |
=item C<nulls> |
|
194 |
|
|
195 |
Either a scalar or a hash reference determining where C<NULL> values |
|
196 |
will be sorted. If undefined then the decision is left to the |
|
197 |
database. |
|
198 |
|
|
199 |
If it is a scalar then all the same value will be used for all |
|
200 |
classes. The value is either C<FIRST> or C<LAST>. |
|
201 |
|
|
202 |
If it is a hash reference then its keys are column names (not SQL |
|
203 |
names). The values are either C<FIRST> or C<LAST>. If a column name is |
|
204 |
not found in this hash then the special keu C<default> will be looked |
|
205 |
up and used if it is found. |
|
206 |
|
|
207 |
Example: |
|
208 |
|
|
209 |
nulls => { transaction_description => 'FIRST', |
|
210 |
customer_name => 'FIRST', |
|
211 |
default => 'LAST', |
|
212 |
}, |
|
213 |
|
|
214 |
=back |
|
215 |
|
|
216 |
=back |
|
217 |
|
|
218 |
=head1 BUGS |
|
219 |
|
|
220 |
Nothing here yet. |
|
221 |
|
|
222 |
=head1 AUTHOR |
|
223 |
|
|
224 |
Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt> |
|
225 |
|
|
226 |
=cut |
SL/DB/Helpers/ALL.pm | ||
---|---|---|
1 |
package SL::DB::Helpers::ALL; |
|
2 |
|
|
3 |
use strict; |
|
4 |
|
|
5 |
use SL::DB::AccTrans; |
|
6 |
use SL::DB::AccTransaction; |
|
7 |
use SL::DB::Assembly; |
|
8 |
use SL::DB::AuditTrail; |
|
9 |
use SL::DB::BankAccount; |
|
10 |
use SL::DB::Bin; |
|
11 |
use SL::DB::Buchungsgruppe; |
|
12 |
use SL::DB::Business; |
|
13 |
use SL::DB::Chart; |
|
14 |
use SL::DB::Contact; |
|
15 |
use SL::DB::CustomVariable; |
|
16 |
use SL::DB::CustomVariableConfig; |
|
17 |
use SL::DB::CustomVariableValidity; |
|
18 |
use SL::DB::Customer; |
|
19 |
use SL::DB::CustomerTax; |
|
20 |
use SL::DB::Datev; |
|
21 |
use SL::DB::Default; |
|
22 |
use SL::DB::DeliveryOrder; |
|
23 |
use SL::DB::DeliveryOrderItem; |
|
24 |
use SL::DB::DeliveryOrderItemsStock; |
|
25 |
use SL::DB::Department; |
|
26 |
use SL::DB::DptTrans; |
|
27 |
use SL::DB::Draft; |
|
28 |
use SL::DB::Dunning; |
|
29 |
use SL::DB::DunningConfig; |
|
30 |
use SL::DB::Employee; |
|
31 |
use SL::DB::Exchangerate; |
|
32 |
use SL::DB::Finanzamt; |
|
33 |
use SL::DB::FollowUp; |
|
34 |
use SL::DB::FollowUpAccess; |
|
35 |
use SL::DB::FollowUpLink; |
|
36 |
use SL::DB::GLTransaction; |
|
37 |
use SL::DB::GenericTranslation; |
|
38 |
use SL::DB::Gifi; |
|
39 |
use SL::DB::History; |
|
40 |
use SL::DB::Inventory; |
|
41 |
use SL::DB::Invoice; |
|
42 |
use SL::DB::InvoiceItem; |
|
43 |
use SL::DB::Language; |
|
44 |
use SL::DB::License; |
|
45 |
use SL::DB::LicenseInvoice; |
|
46 |
use SL::DB::MakeModel; |
|
47 |
use SL::DB::Note; |
|
48 |
use SL::DB::Order; |
|
49 |
use SL::DB::OrderItem; |
|
50 |
use SL::DB::Part; |
|
51 |
use SL::DB::PartsGroup; |
|
52 |
use SL::DB::PartsTax; |
|
53 |
use SL::DB::PaymentTerm; |
|
54 |
use SL::DB::PriceFactor; |
|
55 |
use SL::DB::Pricegroup; |
|
56 |
use SL::DB::Prices; |
|
57 |
use SL::DB::Printer; |
|
58 |
use SL::DB::Project; |
|
59 |
use SL::DB::PurchaseInvoice; |
|
60 |
use SL::DB::RMA; |
|
61 |
use SL::DB::RMAItem; |
|
62 |
use SL::DB::RecordLink; |
|
63 |
use SL::DB::SchemaInfo; |
|
64 |
use SL::DB::SepaExport; |
|
65 |
use SL::DB::SepaExportItem; |
|
66 |
use SL::DB::Shipto; |
|
67 |
use SL::DB::Status; |
|
68 |
use SL::DB::Tax; |
|
69 |
use SL::DB::TaxKey; |
|
70 |
use SL::DB::TaxZone; |
|
71 |
use SL::DB::TodoUserConfig; |
|
72 |
use SL::DB::TransferType; |
|
73 |
use SL::DB::Translation; |
|
74 |
use SL::DB::TranslationPaymentTerm; |
|
75 |
use SL::DB::Unit; |
|
76 |
use SL::DB::UnitsLanguage; |
|
77 |
use SL::DB::Vendor; |
|
78 |
use SL::DB::VendorTax; |
|
79 |
use SL::DB::Warehouse; |
|
80 |
|
|
81 |
1; |
|
82 |
|
|
83 |
__END__ |
|
84 |
|
|
85 |
=pod |
|
86 |
|
|
87 |
=head1 NAME |
|
88 |
|
|
89 |
SL::DB::Helpers::ALL: Dependency-only package for all SL::DB::* modules |
|
90 |
|
|
91 |
=head1 SYNOPSIS |
|
92 |
|
|
93 |
use SL::DB::Helpers::ALL; |
|
94 |
|
|
95 |
=head1 DESCRIPTION |
|
96 |
|
|
97 |
This module depends on all modules in SL/DB/*.pm for the convenience |
|
98 |
of being able to write a simple \C<use SL::DB::Helpers::ALL> and |
|
99 |
having everything loaded. This is supposed to be used only in the |
|
100 |
Lx-Office console. Normal modules should C<use> only the modules they |
|
101 |
actually need. |
|
102 |
|
|
103 |
=head1 AUTHOR |
|
104 |
|
|
105 |
Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt> |
|
106 |
|
|
107 |
=cut |
SL/DB/Helpers/Attr.pm | ||
---|---|---|
1 |
package SL::DB::Helper::Attr; |
|
2 |
|
|
3 |
use strict; |
|
4 |
|
|
5 |
sub auto_make { |
|
6 |
my ($package, %params) = @_; |
|
7 |
|
|
8 |
for my $col ($package->meta->columns) { |
|
9 |
next if $col->primary_key_position; # don't make attr helper for primary keys |
|
10 |
_make_by_type($package, $col->name, $col->type); |
|
11 |
} |
|
12 |
|
|
13 |
return $package; |
|
14 |
} |
|
15 |
|
|
16 |
sub make { |
|
17 |
my ($package, %params) = @_; |
|
18 |
|
|
19 |
for my $name (keys %params) { |
|
20 |
my @types = ref $params{$name} eq 'ARRAY' ? @{ $params{$name} } : ($params{$name}); |
|
21 |
for my $type (@types) { |
|
22 |
_make_by_type($package, $name, $type); |
|
23 |
} |
|
24 |
} |
|
25 |
return $package; |
|
26 |
} |
|
27 |
|
|
28 |
|
|
29 |
|
|
30 |
sub _make_by_type { |
|
31 |
my ($package, $name, $type) = @_; |
|
32 |
_as_number ($package, $name, places => -2) if $type =~ /numeric | real | float/xi; |
|
33 |
_as_percent($package, $name, places => 0) if $type =~ /numeric | real | float/xi; |
|
34 |
_as_number ($package, $name, places => 0) if $type =~ /int/xi; |
|
35 |
_as_date ($package, $name) if $type =~ /date | timestamp/xi; |
|
36 |
} |
|
37 |
|
|
38 |
sub _as_number { |
|
39 |
my $package = shift; |
|
40 |
my $attribute = shift; |
|
41 |
my %params = @_; |
|
42 |
|
|
43 |
$params{places} = 2 if !defined($params{places}); |
|
44 |
|
|
45 |
no strict 'refs'; |
|
46 |
*{ $package . '::' . $attribute . '_as_number' } = sub { |
|
47 |
my ($self, $string) = @_; |
|
48 |
|
|
49 |
$self->$attribute($::form->parse_amount(\%::myconfig, $string)) if @_ > 1; |
|
50 |
|
|
51 |
return $::form->format_amount(\%::myconfig, $self->$attribute, $params{places}); |
|
52 |
}; |
|
53 |
} |
|
54 |
|
|
55 |
sub _as_percent { |
|
56 |
my $package = shift; |
|
57 |
my $attribute = shift; |
|
58 |
my %params = @_; |
|
59 |
|
|
60 |
$params{places} = 2 if !defined($params{places}); |
|
61 |
|
|
62 |
no strict 'refs'; |
|
63 |
*{ $package . '::' . $attribute . '_as_percent' } = sub { |
|
64 |
my ($self, $string) = @_; |
|
65 |
|
|
66 |
$self->$attribute($::form->parse_amount(\%::myconfig, $string) / 100) if @_ > 1; |
|
67 |
|
|
68 |
return $::form->format_amount(\%::myconfig, 100 * $self->$attribute, $params{places}); |
|
69 |
}; |
|
70 |
|
|
71 |
return 1; |
|
72 |
} |
|
73 |
|
|
74 |
sub _as_date { |
|
75 |
my $package = shift; |
|
76 |
my $attribute = shift; |
|
77 |
my %params = @_; |
|
78 |
|
|
79 |
no strict 'refs'; |
|
80 |
*{ $package . '::' . $attribute . '_as_date' } = sub { |
|
81 |
my ($self, $string) = @_; |
|
82 |
|
|
83 |
if (@_ > 1) { |
|
84 |
if ($string) { |
|
85 |
my ($yy, $mm, $dd) = $::locale->parse_date(\%::myconfig, $string); |
|
86 |
$self->$attribute(DateTime->new(year => $yy, month => $mm, day => $dd)); |
|
87 |
} else { |
|
88 |
$self->$attribute(undef); |
|
89 |
} |
|
90 |
} |
|
91 |
|
|
92 |
return $self->$attribute |
|
93 |
? $::locale->reformat_date( |
|
94 |
{ dateformat => 'yy-mm-dd' }, |
|
95 |
( $self->$attribute eq 'now' |
|
96 |
? DateTime->now |
|
97 |
: $self->$attribute |
|
98 |
)->ymd, |
|
99 |
$::myconfig{dateformat} |
|
100 |
) |
|
101 |
: undef; |
|
102 |
}; |
|
103 |
|
|
104 |
return 1; |
|
105 |
} |
|
106 |
|
|
107 |
1; |
|
108 |
|
|
109 |
|
|
110 |
1; |
|
111 |
|
|
112 |
__END__ |
|
113 |
|
|
114 |
=head1 NAME |
|
115 |
|
|
116 |
SL::DB::Helpers::Attr - attribute helpers |
|
117 |
|
|
118 |
=head1 SYNOPSIS |
|
119 |
|
|
120 |
use SL::DB::Helpers::Attr; |
|
121 |
SL::DB::Helpers::Attr::make($class, |
|
122 |
method_name => 'numeric(15,5)', |
|
123 |
datemethod => 'date' |
|
124 |
); |
|
125 |
SL::DB::Helpers::Attr::auto_make($class); |
|
126 |
|
|
127 |
=head1 DESCRIPTION |
|
128 |
|
|
129 |
=head1 FUNCTIONS |
|
130 |
|
|
131 |
=head1 BUGS |
|
132 |
|
|
133 |
=head1 AUTHOR |
|
134 |
|
|
135 |
=cut |
SL/DB/Helpers/ConventionManager.pm | ||
---|---|---|
1 |
package SL::DB::Helpers::ConventionManager; |
|
2 |
|
|
3 |
use strict; |
|
4 |
|
|
5 |
use Rose::DB::Object::ConventionManager; |
|
6 |
|
|
7 |
use base qw(Rose::DB::Object::ConventionManager); |
|
8 |
|
|
9 |
sub auto_manager_class_name { |
|
10 |
my $self = shift; |
|
11 |
my $object_class = shift || $self->meta->class; |
|
12 |
|
|
13 |
my @parts = split m/::/, $object_class; |
|
14 |
my $last = pop @parts; |
|
15 |
|
|
16 |
return join('::', @parts, 'Manager', $last); |
|
17 |
} |
|
18 |
|
|
19 |
# Base name used for 'make_manager_class', e.g. 'get_all', |
|
20 |
# 'update_all' |
|
21 |
sub auto_manager_base_name { |
|
22 |
return 'all'; |
|
23 |
} |
|
24 |
|
|
25 |
sub auto_manager_base_class { |
|
26 |
return 'SL::DB::Helpers::Manager'; |
|
27 |
} |
|
28 |
|
|
29 |
1; |
SL/DB/Helpers/Manager.pm | ||
---|---|---|
1 |
package SL::DB::Helpers::Manager; |
|
2 |
|
|
3 |
use strict; |
|
4 |
|
|
5 |
use Rose::DB::Object::Manager; |
|
6 |
use base qw(Rose::DB::Object::Manager); |
|
7 |
|
|
8 |
sub make_manager_methods { |
|
9 |
my $class = shift; |
|
10 |
my @params = scalar(@_) ? @_ : qw(all); |
|
11 |
return $class->SUPER::make_manager_methods(@params); |
|
12 |
} |
|
13 |
|
|
14 |
sub find_by { |
|
15 |
my $class = shift; |
|
16 |
|
|
17 |
return if !@_; |
|
18 |
return $class->get_all(query => [ @_ ], limit => 1)->[0]; |
|
19 |
} |
|
20 |
|
|
21 |
sub get_first { |
|
22 |
shift->get_all( |
|
23 |
limit => 1, |
|
24 |
)->[0]; |
|
25 |
} |
|
26 |
|
|
27 |
1; |
SL/DB/Helpers/Mappings.pm | ||
---|---|---|
1 |
package SL::DB::Helpers::Mappings; |
|
2 |
|
|
3 |
use utf8; |
|
4 |
use strict; |
|
5 |
|
|
6 |
# these will not be managed as Rose::DB models, because they are not normalized, |
|
7 |
# significant changes are needed to get them done, or they were done by CRM. |
|
8 |
my @lxoffice_blacklist_permanent = qw( |
|
9 |
leads |
|
10 |
); |
|
11 |
|
|
12 |
# these are not managed _yet_, but will hopefully at some point. |
|
13 |
# if you are confident that one of these works, remove it here. |
|
14 |
my @lxoffice_blacklist_temp = qw( |
|
15 |
); |
|
16 |
|
|
17 |
my @lxoffice_blacklist = (@lxoffice_blacklist_permanent, @lxoffice_blacklist_temp); |
|
18 |
|
|
19 |
# map table names to their models. |
|
20 |
# unlike rails we have no singular<->plural magic. |
|
21 |
# remeber: tables should be named as the plural of the model name. |
|
22 |
my %lxoffice_package_names = ( |
|
23 |
acc_trans => 'acc_transaction', |
|
24 |
audittrail => 'audit_trail', |
|
25 |
ar => 'invoice', |
|
26 |
ap => 'purchase_invoice', |
|
27 |
bank_accounts => 'bank_account', |
|
28 |
buchungsgruppen => 'buchungsgruppe', |
|
29 |
contacts => 'contact', |
|
30 |
custom_variable_configs => 'custom_variable_config', |
|
31 |
custom_variables => 'custom_variable', |
|
32 |
custom_variables_validity => 'custom_variable_validity', |
|
33 |
customertax => 'customer_tax', |
|
34 |
datev => 'datev', |
|
35 |
defaults => 'default', |
|
36 |
delivery_orders => 'delivery_order', |
|
37 |
delivery_order_items => 'delivery_order_item', |
|
38 |
department => 'department', |
|
39 |
dpt_trans => 'dpt_trans', |
|
40 |
drafts => 'draft', |
|
41 |
dunning => 'dunning', |
|
42 |
dunning_config => 'dunning_config', |
|
43 |
employee => 'employee', |
|
44 |
exchangerate => 'exchangerate', |
|
45 |
finanzamt => 'finanzamt', |
|
46 |
follow_up_access => 'follow_up_access', |
|
47 |
follow_up_links => 'follow_up_link', |
|
48 |
follow_ups => 'follow_up', |
|
49 |
generic_translations => 'generic_translation', |
|
50 |
gifi => 'gifi', |
|
51 |
gl => 'GLTransaction', |
|
52 |
history_erp => 'history', |
|
53 |
inventory => 'inventory', |
|
54 |
invoice => 'invoice_item', |
|
55 |
language => 'language', |
|
56 |
license => 'license', |
|
57 |
licenseinvoice => 'license_invoice', |
|
58 |
makemodel => 'make_model', |
|
59 |
notes => 'note', |
|
60 |
orderitems => 'order_item', |
|
61 |
oe => 'order', |
|
62 |
parts => 'part', |
|
63 |
partsgroup => 'parts_group', |
|
64 |
partstax => 'parts_tax', |
|
65 |
payment_terms => 'payment_term', |
|
66 |
prices => 'prices', |
|
67 |
price_factors => 'price_factor', |
|
68 |
pricegroup => 'pricegroup', |
|
69 |
printers => 'Printer', |
|
70 |
record_links => 'record_link', |
|
71 |
rma => 'RMA', |
|
72 |
rmaitems => 'RMA_item', |
|
73 |
sepa_export => 'sepa_export', |
|
74 |
sepa_export_items => 'sepa_export_item', |
|
75 |
schema_info => 'schema_info', |
|
76 |
status => 'status', |
|
77 |
tax => 'tax', |
|
78 |
taxkeys => 'tax_key', |
|
79 |
tax_zones => 'tax_zone', |
|
80 |
todo_user_config => 'todo_user_config', |
|
81 |
translation => 'translation', |
|
82 |
translation_payment_terms => 'translation_payment_term', |
|
83 |
units => 'unit', |
|
84 |
units_language => 'units_language', |
|
85 |
vendortax => 'vendor_tax', |
|
86 |
); |
|
87 |
|
|
88 |
sub get_blacklist { |
|
89 |
return LXOFFICE => \@lxoffice_blacklist; |
|
90 |
} |
|
91 |
|
|
92 |
sub get_package_names { |
|
93 |
return LXOFFICE => \%lxoffice_package_names; |
|
94 |
} |
|
95 |
|
|
96 |
sub db { |
|
97 |
my $string = $_[0]; |
|
98 |
my $lookup = $lxoffice_package_names{$_[0]} || |
|
99 |
plurify($lxoffice_package_names{singlify($_[0])}); |
|
100 |
|
|
101 |
for my $thing ($string, $lookup) { |
|
102 |
|
|
103 |
# best guess? its already the name. like part. camelize it first |
|
104 |
my $class = "SL::DB::" . camelify($thing); |
|
105 |
return $class if defined *{ $class. '::' }; |
|
106 |
|
|
107 |
# next, someone wants a manager and pluralized. |
|
108 |
my $manager = "SL::DB::Manager::" . singlify(camelify($thing)); |
|
109 |
return $manager if defined *{ $manager . '::' }; |
|
110 |
} |
|
111 |
|
|
112 |
die "Can't resolve '$string' as a database model, sorry. Did you perhaps forgot to load it?"; |
|
113 |
} |
|
114 |
|
|
115 |
sub camelify { |
|
116 |
my ($str) = @_; |
|
117 |
$str =~ s/_+(.)/uc($1)/ge; |
|
118 |
ucfirst $str; |
|
119 |
} |
|
120 |
|
|
121 |
sub snakify { |
|
122 |
my ($str) = @_; |
|
123 |
$str =~ s/(?<!^)\u(.)/'_' . lc($1)/ge; |
|
124 |
lcfirst $str; |
|
125 |
} |
|
126 |
|
|
127 |
sub plurify { |
|
128 |
my ($str) = @_; |
|
129 |
$str . 's'; |
|
130 |
} |
|
131 |
|
|
132 |
sub singlify { |
|
133 |
my ($str) = @_; |
|
134 |
local $/ = 's'; |
|
135 |
chomp $str; |
|
136 |
$str; |
|
137 |
} |
|
138 |
|
|
139 |
1; |
|
140 |
|
|
141 |
__END__ |
|
142 |
|
|
143 |
=head1 NAME |
|
144 |
|
|
145 |
SL::DB::Helpers::Mappings - Rose Table <-> Model mapping information |
|
146 |
|
|
147 |
=head1 SYNOPSIS |
|
148 |
|
|
149 |
use SL::DB::Helpers::Mappings qw(@blacklist %table2model); |
|
150 |
|
|
151 |
=head1 DESCRIPTION |
|
152 |
|
|
153 |
This modul stores table <-> model mappings used by the |
|
154 |
L<scripts/rose_auto_create_model.pl> script. If you add a new table that has |
|
155 |
custom mappings, add it here. |
|
156 |
|
|
157 |
=head2 db |
|
158 |
|
|
159 |
A special function provided here is E<db>. Without it you'd have to write: |
|
160 |
|
|
161 |
my $part = SL::DB::Part->new(id => 1234); |
|
162 |
my @all_parts = SL::DB::Manager::Part->get_all; |
|
163 |
|
|
164 |
with them it becomes: |
|
165 |
|
|
166 |
my $part = db('part')->new(id => 123); |
|
167 |
my @all_parts = db('parts')->get_all; |
|
168 |
|
|
169 |
You don't have to care about add that SL::DB:: incantation anymore. Also, a |
|
170 |
simple s at the end will get you the associated Manager class. |
|
171 |
|
|
172 |
db is written to try to make sense of what you give it, but if all fails, it |
|
173 |
will die with an error. |
|
174 |
|
|
175 |
=head1 BUGS |
|
176 |
|
|
177 |
nothing yet |
|
178 |
|
|
179 |
=head1 SEE ALSO |
|
180 |
|
|
181 |
L<scripts/rose_auto_create_model.pl> |
|
182 |
|
|
183 |
=head1 AUTHOR |
|
184 |
|
|
185 |
Sven Schöling <s.schoeling@linet-services.de> |
|
186 |
|
|
187 |
=cut |
SL/DB/Helpers/Metadata.pm | ||
---|---|---|
1 |
package SL::DB::Helpers::Metadata; |
|
2 |
|
|
3 |
use strict; |
|
4 |
|
|
5 |
use Rose::DB::Object::Metadata; |
|
6 |
use SL::DB::Helpers::ConventionManager; |
|
7 |
|
|
8 |
use base qw(Rose::DB::Object::Metadata); |
|
9 |
|
|
10 |
sub convention_manager_class { |
|
11 |
return 'SL::DB::Helpers::ConventionManager'; |
|
12 |
} |
|
13 |
|
|
14 |
sub default_manager_base_class { |
|
15 |
return 'SL::DB::Helpers::Manager'; |
|
16 |
} |
|
17 |
|
|
18 |
sub initialize { |
|
19 |
my $self = shift; |
|
20 |
$self->make_attr_auto_helpers unless $self->is_initialized; |
|
21 |
$self->SUPER::initialize(@_); |
|
22 |
} |
|
23 |
|
|
24 |
sub make_attr_helpers { |
|
25 |
my ($self, %params) = @_; |
|
26 |
SL::DB::Helper::Attr::make($self->class, %params); |
|
27 |
} |
|
28 |
|
|
29 |
sub make_attr_auto_helpers { |
|
30 |
my ($self) = @_; |
|
31 |
SL::DB::Helper::Attr::auto_make($self->class); |
|
32 |
} |
|
33 |
|
|
34 |
1; |
SL/DB/Helpers/Sorted.pm | ||
---|---|---|
1 |
package SL::DB::Helpers::Sorted; |
|
2 |
|
|
3 |
use strict; |
|
4 |
|
|
5 |
require Exporter; |
|
6 |
our @ISA = qw(Exporter); |
|
7 |
our @EXPORT = qw(get_all_sorted make_sort_string); |
|
8 |
|
|
9 |
my %sort_spec; |
|
10 |
|
|
11 |
sub make_sort_string { |
|
12 |
my ($class, %params) = @_; |
|
13 |
|
|
14 |
my $sort_spec = _get_sort_spec($class); |
|
15 |
|
|
16 |
my $sort_dir = defined($params{sort_dir}) ? $params{sort_dir} * 1 : $sort_spec->{default}->[1]; |
|
17 |
my $sort_dir_str = $sort_dir ? 'ASC' : 'DESC'; |
|
18 |
|
|
19 |
my $sort_by = $params{sort_by}; |
|
20 |
$sort_by = $sort_spec->{default}->[0] unless $sort_spec->{columns}->{$sort_by}; |
|
21 |
|
|
22 |
my $nulls_str = ''; |
|
23 |
if ($sort_spec->{nulls}) { |
|
24 |
$nulls_str = ref($sort_spec->{nulls}) ? ($sort_spec->{nulls}->{$sort_by} || $sort_spec->{nulls}->{default}) : $sort_spec->{nulls}; |
|
25 |
$nulls_str = " NULLS ${nulls_str}" if $nulls_str; |
|
26 |
} |
|
27 |
|
|
28 |
my $sort_by_str = $sort_spec->{columns}->{$sort_by}; |
|
29 |
$sort_by_str = [ $sort_by_str ] unless ref($sort_by_str) eq 'ARRAY'; |
|
30 |
$sort_by_str = join(', ', map { "${_} ${sort_dir_str}${nulls_str}" } @{ $sort_by_str }); |
|
31 |
|
|
32 |
return wantarray ? ($sort_by, $sort_dir, $sort_by_str) : $sort_by_str; |
|
33 |
} |
|
34 |
|
|
35 |
sub get_all_sorted { |
|
36 |
my ($class, %params) = @_; |
|
37 |
my $sort_str = $class->make_sort_string(sort_by => delete($params{sort_by}), sort_dir => delete($params{sort_dir})); |
|
38 |
|
|
39 |
return $class->get_all(sort_by => $sort_str, %params); |
|
40 |
} |
|
41 |
|
|
42 |
sub _get_sort_spec { |
|
43 |
my ($class) = @_; |
|
44 |
return $sort_spec{$class} ||= _make_sort_spec($class); |
|
45 |
} |
|
46 |
|
|
47 |
sub _make_sort_spec { |
|
48 |
my ($class) = @_; |
|
49 |
|
|
50 |
my %sort_spec = $class->_sort_spec if defined &{ "${class}::_sort_spec" }; |
|
51 |
|
|
52 |
my $meta = $class->object_class->meta; |
|
53 |
|
|
54 |
if (!$sort_spec{default}) { |
|
55 |
my @primary_keys = $meta->primary_key; |
|
56 |
$sort_spec{default} = [ "" . $primary_keys[0], 1 ]; |
|
57 |
} |
|
58 |
|
|
59 |
$sort_spec{columns} ||= { SIMPLE => [ map { "$_" } $meta->columns ] }; |
|
60 |
|
|
61 |
if ($sort_spec{columns}->{SIMPLE}) { |
|
62 |
my $table = $meta->table; |
|
63 |
|
|
64 |
if (!ref($sort_spec{columns}->{SIMPLE}) && ($sort_spec{columns}->{SIMPLE} eq 'ALL')) { |
|
65 |
map { $sort_spec{columns}->{"$_"} ||= "${table}.${_}"} @{ $meta->columns }; |
|
66 |
delete $sort_spec{columns}->{SIMPLE}; |
|
67 |
} else { |
|
68 |
map { $sort_spec{columns}->{$_} = "${table}.${_}" } @{ delete($sort_spec{columns}->{SIMPLE}) }; |
|
69 |
} |
|
70 |
} |
|
71 |
|
|
72 |
return \%sort_spec; |
|
73 |
} |
|
74 |
|
|
75 |
1; |
|
76 |
|
|
77 |
__END__ |
|
78 |
|
|
79 |
=encoding utf8 |
|
80 |
|
|
81 |
=head1 NAME |
|
82 |
|
|
83 |
SL::DB::Helpers::Sorted - Mixin for a manager class that handles |
|
84 |
sorting of database records |
|
85 |
|
|
86 |
=head1 SYNOPSIS |
|
87 |
|
|
88 |
package SL::DB::Manager::Message; |
|
89 |
|
|
90 |
use SL::DB::Helpers::Sorted; |
|
91 |
|
|
92 |
sub _sort_spec { |
|
93 |
return ( columns => { recipient_id => [ 'CASE |
|
94 |
WHEN recipient_group_id IS NULL THEN lower(recipient.name) |
|
95 |
ELSE lower(recipient_group.name) |
|
96 |
END', ], |
|
97 |
sender_id => [ 'lower(sender.name)', ], |
|
98 |
created_at => [ 'created_at', ], |
|
99 |
subject => [ 'lower(subject)', ], |
|
100 |
status => [ 'NOT COALESCE(unread, FALSE)', 'created_at' ], |
|
101 |
}, |
|
102 |
default => [ 'status', 1 ], |
|
103 |
nulls => { default => 'LAST', |
|
104 |
subject => 'FIRST', |
|
105 |
} |
|
106 |
); |
|
107 |
} |
|
108 |
|
|
109 |
package SL::Controller::Message; |
|
110 |
|
|
111 |
sub action_list { |
|
112 |
my $messages = SL::DB::Manager::Message->get_all_sorted(sort_by => $::form->{sort_by}, |
|
113 |
sort_dir => $::form->{sort_dir}); |
|
114 |
} |
|
115 |
|
|
116 |
=head1 CLASS FUNCTIONS |
|
117 |
|
|
118 |
=over 4 |
|
119 |
|
|
120 |
=item C<make_sort_string %params> |
|
121 |
|
|
122 |
Evaluates C<$params{sort_by}> and C<$params{sort_dir}> and returns an |
|
123 |
SQL string suitable for sorting. The package this package is mixed |
|
124 |
into has to provide a method L</_sort_spec> that returns a hash whose |
|
125 |
structure is explained below. That hash is authoritive in which |
|
126 |
columns may be sorted, which column to sort by by default and how to |
|
127 |
handle C<NULL> values. |
|
128 |
|
|
129 |
Returns the SQL string in scalar context. In array context it returns |
|
130 |
three values: the actual column it sorts by (suitable for another call |
|
131 |
to L</make_sort_string>), the actual sort direction (either 0 or 1) |
|
132 |
and the SQL string. |
|
133 |
|
|
134 |
=item C<get_all_sorted %params> |
|
135 |
|
|
136 |
Returns C<< $class->get_all >> with C<sort_by> set to the value |
|
137 |
returned by c<< $class->make_sort_string(%params) >>. |
|
138 |
|
|
139 |
=back |
|
140 |
|
|
141 |
=head1 CLASS FUNCTIONS PROVIDED BY THE MIXING PACKAGE |
|
142 |
|
|
143 |
=over 4 |
|
144 |
|
|
145 |
=item C<_sort_spec> |
|
146 |
|
|
147 |
This method is actually not part of this package but can be provided |
Auch abrufbar als: Unified diff
Verzeichnis SL/DB/Helpers in SL/DB/Helper umbenannt (Konsistenz)