33 |
33 |
use SL::Helper::UserPreferences::UpdatePositions;
|
34 |
34 |
|
35 |
35 |
use SL::Controller::Helper::GetModels;
|
|
36 |
use SL::Controller::DeliveryOrder::TypeData;
|
36 |
37 |
|
37 |
38 |
use List::Util qw(first sum0);
|
38 |
39 |
use List::UtilsBy qw(sort_by uniq_by);
|
... | ... | |
65 |
66 |
my ($self) = @_;
|
66 |
67 |
|
67 |
68 |
$self->order->transdate(DateTime->now_local());
|
68 |
|
my $extra_days = $self->type eq sales_quotation_type() ? $::instance_conf->get_reqdate_interval :
|
69 |
|
$self->type eq sales_order_type() ? $::instance_conf->get_delivery_date_interval : 1;
|
70 |
|
|
71 |
|
if ( ($self->type eq sales_order_type() && $::instance_conf->get_deliverydate_on)
|
72 |
|
|| ($self->type eq sales_quotation_type() && $::instance_conf->get_reqdate_on)
|
73 |
|
&& (!$self->order->reqdate)) {
|
74 |
|
$self->order->reqdate(DateTime->today_local->next_workday(extra_days => $extra_days));
|
75 |
|
}
|
|
69 |
$self->set_reqdate_by_type;
|
76 |
70 |
|
77 |
71 |
|
78 |
72 |
$self->pre_render();
|
... | ... | |
152 |
146 |
return $self->js->render();
|
153 |
147 |
}
|
154 |
148 |
|
155 |
|
my $text = $self->type eq sales_order_type() ? $::locale->text('The order has been deleted')
|
156 |
|
: $self->type eq purchase_order_type() ? $::locale->text('The order has been deleted')
|
157 |
|
: $self->type eq sales_quotation_type() ? $::locale->text('The quotation has been deleted')
|
158 |
|
: $self->type eq request_quotation_type() ? $::locale->text('The rfq has been deleted')
|
159 |
|
: '';
|
160 |
|
flash_later('info', $text);
|
|
149 |
flash_later('info', $self->type_data->text("delete"));
|
161 |
150 |
|
162 |
151 |
my @redirect_params = (
|
163 |
152 |
action => 'add',
|
... | ... | |
178 |
167 |
return $self->js->render();
|
179 |
168 |
}
|
180 |
169 |
|
181 |
|
my $text = $self->type eq sales_order_type() ? $::locale->text('The order has been saved')
|
182 |
|
: $self->type eq purchase_order_type() ? $::locale->text('The order has been saved')
|
183 |
|
: $self->type eq sales_quotation_type() ? $::locale->text('The quotation has been saved')
|
184 |
|
: $self->type eq request_quotation_type() ? $::locale->text('The rfq has been saved')
|
185 |
|
: '';
|
186 |
|
flash_later('info', $text);
|
|
170 |
flash_later('info', $self->type_data->text("saved"));
|
187 |
171 |
|
188 |
172 |
my @redirect_params = (
|
189 |
173 |
action => 'edit',
|
... | ... | |
221 |
205 |
: $order->transdate;
|
222 |
206 |
|
223 |
207 |
# Set new reqdate unless changed if it is enabled in client config
|
224 |
|
if ($order->reqdate == $saved_order->reqdate) {
|
225 |
|
my $extra_days = $self->type eq sales_quotation_type() ? $::instance_conf->get_reqdate_interval :
|
226 |
|
$self->type eq sales_order_type() ? $::instance_conf->get_delivery_date_interval : 1;
|
227 |
|
|
228 |
|
if ( ($self->type eq sales_order_type() && !$::instance_conf->get_deliverydate_on)
|
229 |
|
|| ($self->type eq sales_quotation_type() && !$::instance_conf->get_reqdate_on)) {
|
230 |
|
$new_attrs{reqdate} = '';
|
231 |
|
} else {
|
232 |
|
$new_attrs{reqdate} = DateTime->today_local->next_workday(extra_days => $extra_days);
|
233 |
|
}
|
234 |
|
} else {
|
235 |
|
$new_attrs{reqdate} = $order->reqdate;
|
236 |
|
}
|
|
208 |
$new_attrs{reqdate} = $self->get_reqdate_by_type($order->reqdate, $saved_order->reqdate);
|
237 |
209 |
|
238 |
210 |
# Update employee
|
239 |
211 |
$new_attrs{employee} = SL::DB::Manager::Employee->current;
|
... | ... | |
1049 |
1021 |
# helpers
|
1050 |
1022 |
#
|
1051 |
1023 |
|
1052 |
|
sub init_valid_types {
|
1053 |
|
[ sales_order_type(), purchase_order_type(), sales_quotation_type(), request_quotation_type() ];
|
1054 |
|
}
|
1055 |
|
|
1056 |
1024 |
sub init_type {
|
1057 |
1025 |
my ($self) = @_;
|
1058 |
1026 |
|
... | ... | |
1066 |
1034 |
sub init_cv {
|
1067 |
1035 |
my ($self) = @_;
|
1068 |
1036 |
|
1069 |
|
my $cv = (any { $self->type eq $_ } (sales_order_type(), sales_quotation_type())) ? 'customer'
|
1070 |
|
: (any { $self->type eq $_ } (purchase_order_type(), request_quotation_type())) ? 'vendor'
|
1071 |
|
: die "Not a valid type for order";
|
1072 |
|
|
1073 |
|
return $cv;
|
|
1037 |
return $self->type_data->customervendor;
|
1074 |
1038 |
}
|
1075 |
1039 |
|
1076 |
1040 |
sub init_search_cvpartnumber {
|
... | ... | |
1104 |
1068 |
|
1105 |
1069 |
sub init_part_picker_classification_ids {
|
1106 |
1070 |
my ($self) = @_;
|
1107 |
|
my $attribute = 'used_for_' . ($self->type =~ m{sales} ? 'sale' : 'purchase');
|
1108 |
1071 |
|
1109 |
|
return [ map { $_->id } @{ SL::DB::Manager::PartClassification->get_all(where => [ $attribute => 1 ]) } ];
|
|
1072 |
return [ map { $_->id } @{ SL::DB::Manager::PartClassification->get_all(where => $self->type_date->part_classification_query) } ];
|
1110 |
1073 |
}
|
1111 |
1074 |
|
1112 |
1075 |
sub check_auth {
|
1113 |
1076 |
my ($self) = @_;
|
1114 |
1077 |
|
1115 |
|
my $right_for = { map { $_ => $_.'_edit' } @{$self->valid_types} };
|
1116 |
|
|
1117 |
|
my $right = $right_for->{ $self->type };
|
1118 |
|
$right ||= 'DOES_NOT_EXIST';
|
1119 |
|
|
1120 |
|
$::auth->assert($right);
|
|
1078 |
$::auth->assert($self->type_data->access || 'DOES_NOT_EXIST');
|
1121 |
1079 |
}
|
1122 |
1080 |
|
1123 |
1081 |
# build the selection box for contacts
|
... | ... | |
1204 |
1162 |
my $order;
|
1205 |
1163 |
$order = SL::DB::DeliveryOrder->new(id => $::form->{id})->load(with => [ 'orderitems', 'orderitems.part' ]) if $::form->{id};
|
1206 |
1164 |
$order ||= SL::DB::DeliveryOrder->new(orderitems => [],
|
1207 |
|
quotation => (any { $self->type eq $_ } (sales_quotation_type(), request_quotation_type())),
|
|
1165 |
quotation => $self->type_data->is_quotation,
|
1208 |
1166 |
currency_id => $::instance_conf->get_currency_id(),);
|
1209 |
1167 |
|
1210 |
1168 |
my $cv_id_method = $self->cv . '_id';
|
... | ... | |
1485 |
1443 |
return $self->js->render();
|
1486 |
1444 |
}
|
1487 |
1445 |
|
1488 |
|
my $destination_type = $::form->{type} eq sales_order_type() ? sales_quotation_type() : request_quotation_type();
|
|
1446 |
my $destination_type = $self->type_data->workflow("to_quotation_type");
|
1489 |
1447 |
|
1490 |
1448 |
$self->order(SL::DB::DeliveryOrder->new_from($self->order, destination_type => $destination_type));
|
1491 |
1449 |
$self->{converted_from_oe_id} = delete $::form->{id};
|
... | ... | |
1527 |
1485 |
return $self->js->render();
|
1528 |
1486 |
}
|
1529 |
1487 |
|
1530 |
|
my $destination_type = $::form->{type} eq sales_quotation_type() ? sales_order_type()
|
1531 |
|
: $::form->{type} eq request_quotation_type() ? purchase_order_type()
|
1532 |
|
: $::form->{type} eq purchase_order_type() ? sales_order_type()
|
1533 |
|
: $::form->{type} eq sales_order_type() ? purchase_order_type()
|
1534 |
|
: '';
|
|
1488 |
my $destination_type = $self->type_data->workflow("to_order_type");
|
1535 |
1489 |
|
1536 |
1490 |
# check for direct delivery
|
1537 |
1491 |
# copy shipto in custom shipto (custom shipto will be copied by new_from() in case)
|
1538 |
1492 |
my $custom_shipto;
|
1539 |
|
if ( $::form->{type} eq sales_order_type() && $destination_type eq purchase_order_type()
|
1540 |
|
&& $::form->{use_shipto} && $self->order->shipto) {
|
|
1493 |
if ($self->type_data->workflow("to_order_copy_shipto") && $::form->{use_shipto} && $self->order->shipto) {
|
1541 |
1494 |
$custom_shipto = $self->order->shipto->clone('SL::DB::DeliveryOrder');
|
1542 |
1495 |
}
|
1543 |
1496 |
|
... | ... | |
1549 |
1502 |
$item->{new_fake_id} = join('_', 'new', Time::HiRes::gettimeofday(), int rand 1000000000000);
|
1550 |
1503 |
}
|
1551 |
1504 |
|
1552 |
|
if ($::form->{type} eq sales_order_type() && $destination_type eq purchase_order_type()) {
|
|
1505 |
if ($self->type_data->workflow("to_order_copy_shipto")) {
|
1553 |
1506 |
if ($::form->{use_shipto}) {
|
1554 |
1507 |
$self->order->custom_shipto($custom_shipto) if $custom_shipto;
|
1555 |
1508 |
} else {
|
... | ... | |
1619 |
1572 |
$item->active_discount_source($price_source->discount_from_source($item->active_discount_source));
|
1620 |
1573 |
}
|
1621 |
1574 |
|
1622 |
|
if (any { $self->type eq $_ } (sales_order_type(), purchase_order_type())) {
|
1623 |
|
# Calculate shipped qtys here to prevent calling calculate for every item via the items method.
|
1624 |
|
# Do not use write_to_objects to prevent order->delivered to be set, because this should be
|
1625 |
|
# the value from db, which can be set manually or is set when linked delivery orders are saved.
|
1626 |
|
SL::Helper::ShippedQty->new->calculate($self->order)->write_to(\@{$self->order->items});
|
1627 |
|
}
|
1628 |
|
|
1629 |
1575 |
if ($self->order->number && $::instance_conf->get_webdav) {
|
1630 |
1576 |
my $webdav = SL::Webdav->new(
|
1631 |
1577 |
type => $self->type,
|
... | ... | |
1648 |
1594 |
sub setup_edit_action_bar {
|
1649 |
1595 |
my ($self, %params) = @_;
|
1650 |
1596 |
|
1651 |
|
my $deletion_allowed = (any { $self->type eq $_ } (sales_quotation_type(), request_quotation_type()))
|
1652 |
|
|| (($self->type eq sales_order_type()) && $::instance_conf->get_sales_order_show_delete)
|
1653 |
|
|| (($self->type eq purchase_order_type()) && $::instance_conf->get_purchase_order_show_delete);
|
|
1597 |
my $deletion_allowed = $self->type_data->show_menu("delete");
|
1654 |
1598 |
|
1655 |
1599 |
for my $bar ($::request->layout->get('actionbar')) {
|
1656 |
1600 |
$bar->add(
|
... | ... | |
1675 |
1619 |
action => [
|
1676 |
1620 |
t8('Save and Quotation'),
|
1677 |
1621 |
submit => [ '#order_form', { action => "DeliveryOrder/sales_quotation" } ],
|
1678 |
|
only_if => (any { $self->type eq $_ } (sales_order_type())),
|
|
1622 |
only_if => $self->type_data->show_menu("save_and_quotation"),
|
1679 |
1623 |
],
|
1680 |
1624 |
action => [
|
1681 |
1625 |
t8('Save and RFQ'),
|
1682 |
1626 |
submit => [ '#order_form', { action => "DeliveryOrder/request_for_quotation" } ],
|
1683 |
|
only_if => (any { $self->type eq $_ } (purchase_order_type())),
|
|
1627 |
only_if => $self->type_data->show_menu("save_and_rfq"),
|
1684 |
1628 |
],
|
1685 |
1629 |
action => [
|
1686 |
1630 |
t8('Save and Sales Order'),
|
1687 |
1631 |
submit => [ '#order_form', { action => "DeliveryOrder/sales_order" } ],
|
1688 |
|
only_if => (any { $self->type eq $_ } (sales_quotation_type(), purchase_order_type())),
|
|
1632 |
only_if => $self->type_data->show_menu("save_and_sales_order"),
|
1689 |
1633 |
],
|
1690 |
1634 |
action => [
|
1691 |
1635 |
t8('Save and Purchase Order'),
|
1692 |
1636 |
call => [ 'kivi.Order.purchase_order_check_for_direct_delivery' ],
|
1693 |
|
only_if => (any { $self->type eq $_ } (sales_order_type(), request_quotation_type())),
|
|
1637 |
only_if => $self->type_data->show_menu("save_and_purchase_order"),
|
1694 |
1638 |
],
|
1695 |
1639 |
action => [
|
1696 |
1640 |
t8('Save and Delivery Order'),
|
1697 |
1641 |
call => [ 'kivi.Order.save', 'save_and_delivery_order', $::instance_conf->get_order_warn_duplicate_parts,
|
1698 |
1642 |
$::instance_conf->get_order_warn_no_deliverydate,
|
1699 |
1643 |
],
|
1700 |
|
only_if => (any { $self->type eq $_ } (sales_order_type(), purchase_order_type()))
|
|
1644 |
only_if => $self->type_data->show_menu("save_and_delivery_order"),
|
1701 |
1645 |
],
|
1702 |
1646 |
action => [
|
1703 |
1647 |
t8('Save and Invoice'),
|
... | ... | |
1706 |
1650 |
action => [
|
1707 |
1651 |
t8('Save and AP Transaction'),
|
1708 |
1652 |
call => [ 'kivi.Order.save', 'save_and_ap_transaction', $::instance_conf->get_order_warn_duplicate_parts ],
|
1709 |
|
only_if => (any { $self->type eq $_ } (purchase_order_type()))
|
|
1653 |
only_if => $self->type_data->show_menu("save_and_ap_transaction"),
|
1710 |
1654 |
],
|
1711 |
1655 |
|
1712 |
1656 |
], # end of combobox "Workflow"
|
... | ... | |
1748 |
1692 |
call => [ 'kivi.Order.delete_order' ],
|
1749 |
1693 |
confirm => $::locale->text('Do you really want to delete this object?'),
|
1750 |
1694 |
disabled => !$self->order->id ? t8('This object has not been saved yet.') : undef,
|
1751 |
|
only_if => $deletion_allowed,
|
|
1695 |
only_if => $self->type_data->show_menu("delete"),
|
1752 |
1696 |
],
|
1753 |
1697 |
|
1754 |
1698 |
combobox => [
|
... | ... | |
1869 |
1813 |
my ($self, $action) = @_;
|
1870 |
1814 |
|
1871 |
1815 |
return '' if none { lc($action)} qw(add edit);
|
1872 |
|
|
1873 |
|
# for locales:
|
1874 |
|
# $::locale->text("Add Sales Order");
|
1875 |
|
# $::locale->text("Add Purchase Order");
|
1876 |
|
# $::locale->text("Add Quotation");
|
1877 |
|
# $::locale->text("Add Request for Quotation");
|
1878 |
|
# $::locale->text("Edit Sales Order");
|
1879 |
|
# $::locale->text("Edit Purchase Order");
|
1880 |
|
# $::locale->text("Edit Quotation");
|
1881 |
|
# $::locale->text("Edit Request for Quotation");
|
1882 |
|
|
1883 |
|
$action = ucfirst(lc($action));
|
1884 |
|
return $self->type eq sales_order_type() ? $::locale->text("$action Sales Order")
|
1885 |
|
: $self->type eq purchase_order_type() ? $::locale->text("$action Purchase Order")
|
1886 |
|
: $self->type eq sales_quotation_type() ? $::locale->text("$action Quotation")
|
1887 |
|
: $self->type eq request_quotation_type() ? $::locale->text("$action Request for Quotation")
|
1888 |
|
: '';
|
|
1816 |
return $self->type_data->text($action);
|
1889 |
1817 |
}
|
1890 |
1818 |
|
1891 |
1819 |
sub get_item_cvpartnumber {
|
... | ... | |
1927 |
1855 |
return $texts;
|
1928 |
1856 |
}
|
1929 |
1857 |
|
1930 |
|
sub sales_order_type {
|
1931 |
|
'sales_order';
|
1932 |
|
}
|
1933 |
|
|
1934 |
|
sub purchase_order_type {
|
1935 |
|
'purchase_order';
|
1936 |
|
}
|
1937 |
|
|
1938 |
|
sub sales_quotation_type {
|
1939 |
|
'sales_quotation';
|
1940 |
|
}
|
1941 |
|
|
1942 |
|
sub request_quotation_type {
|
1943 |
|
'request_quotation';
|
1944 |
|
}
|
1945 |
|
|
1946 |
1858 |
sub nr_key {
|
1947 |
|
return $_[0]->type eq sales_order_type() ? 'ordnumber'
|
1948 |
|
: $_[0]->type eq purchase_order_type() ? 'ordnumber'
|
1949 |
|
: $_[0]->type eq sales_quotation_type() ? 'quonumber'
|
1950 |
|
: $_[0]->type eq request_quotation_type() ? 'quonumber'
|
1951 |
|
: '';
|
|
1859 |
return $_[0]->type_data->nr_key;
|
1952 |
1860 |
}
|
1953 |
1861 |
|
1954 |
1862 |
sub save_and_redirect_to {
|
... | ... | |
1961 |
1869 |
return $self->js->render();
|
1962 |
1870 |
}
|
1963 |
1871 |
|
1964 |
|
my $text = $self->type eq sales_order_type() ? $::locale->text('The order has been saved')
|
1965 |
|
: $self->type eq purchase_order_type() ? $::locale->text('The order has been saved')
|
1966 |
|
: $self->type eq sales_quotation_type() ? $::locale->text('The quotation has been saved')
|
1967 |
|
: $self->type eq request_quotation_type() ? $::locale->text('The rfq has been saved')
|
1968 |
|
: '';
|
1969 |
|
flash_later('info', $text);
|
|
1872 |
flash_later('info', $self->type_data->text("saved"));
|
1970 |
1873 |
|
1971 |
1874 |
$self->redirect_to(%params, id => $self->order->id);
|
1972 |
1875 |
}
|
... | ... | |
1974 |
1877 |
sub save_history {
|
1975 |
1878 |
my ($self, $addition) = @_;
|
1976 |
1879 |
|
1977 |
|
my $number_type = $self->order->type =~ m{order} ? 'ordnumber' : 'quonumber';
|
|
1880 |
my $number_type = $self->nr_key;
|
1978 |
1881 |
my $snumbers = $number_type . '_' . $self->order->$number_type;
|
1979 |
1882 |
|
1980 |
1883 |
SL::DB::History->new(
|
... | ... | |
2026 |
1929 |
return @errors;
|
2027 |
1930 |
}
|
2028 |
1931 |
|
|
1932 |
sub init_type_data {
|
|
1933 |
SL::Controller::DeliveryOrder::TypeData->new($_[0]);
|
|
1934 |
}
|
|
1935 |
|
|
1936 |
sub init_valid_types {
|
|
1937 |
$_[0]->type_data->valid_types;
|
|
1938 |
}
|
|
1939 |
|
2029 |
1940 |
1;
|
2030 |
1941 |
|
2031 |
1942 |
__END__
|
DeliveryOrder: type data zentralisiert um das verhalten besser generalisieren zu können