[IMP] point_of_sale: add date picker to ship later option

In order to plan a certain Ship Later pos order, a user must go to the backend and find the correct picking linked to the order he made. The date picker can be useful to not have to go back to the backend and continue selling to customers.

Now, when pushing on the button Ship Later, a date picker appears with a default date set as the current date and the user can chose another date after the default date.

closes odoo/odoo#107115

Task-id: 3078526
Related: odoo/upgrade#4200
Signed-off-by: Trinh Jacky (trj) <trj@odoo.com>
This commit is contained in:
Adrien Guilliams (adgu)
2023-01-12 19:08:40 +01:00
parent b4b390d410
commit fe9e230b50
12 changed files with 136 additions and 24 deletions
+9 -5
View File
@@ -52,7 +52,7 @@ class PosOrder(models.Model):
'amount_return': ui_order['amount_return'],
'company_id': self.env['pos.session'].browse(ui_order['pos_session_id']).company_id.id,
'to_invoice': ui_order['to_invoice'] if "to_invoice" in ui_order else False,
'to_ship': ui_order['to_ship'] if "to_ship" in ui_order else False,
'shipping_date': ui_order['shipping_date'] if "shipping_date" in ui_order else False,
'is_tipped': ui_order.get('is_tipped', False),
'tip_amount': ui_order.get('tip_amount', 0),
'access_token': ui_order.get('access_token', '')
@@ -284,7 +284,7 @@ class PosOrder(models.Model):
payment_ids = fields.One2many('pos.payment', 'pos_order_id', string='Payments', readonly=True)
session_move_id = fields.Many2one('account.move', string='Session Journal Entry', related='session_id.move_id', readonly=True, copy=False)
to_invoice = fields.Boolean('To invoice', copy=False)
to_ship = fields.Boolean('To ship')
shipping_date = fields.Date('Shipping Date')
is_invoiced = fields.Boolean('Is Invoiced', compute='_compute_is_invoiced')
is_tipped = fields.Boolean('Is this already tipped?', readonly=True)
tip_amount = fields.Float(string='Tip Amount', digits=0, readonly=True)
@@ -887,7 +887,7 @@ class PosOrder(models.Model):
def _create_order_picking(self):
self.ensure_one()
if self.to_ship:
if self.shipping_date:
self.lines._launch_stock_rule_from_pos_order_lines()
else:
if self._should_create_picking_real_time():
@@ -1028,7 +1028,7 @@ class PosOrder(models.Model):
'creation_date': order.date_order.astimezone(timezone),
'fiscal_position_id': order.fiscal_position_id.id,
'to_invoice': order.to_invoice,
'to_ship': order.to_ship,
'shipping_date': order.shipping_date,
'state': order.state,
'account_move': order.account_move.id,
'id': order.id,
@@ -1238,7 +1238,11 @@ class PosOrderLine(models.Model):
"""
self.ensure_one()
# Use the delivery date if there is else use date_order and lead time
date_deadline = self.order_id.date_order
if self.order_id.shipping_date:
date_deadline = self.order_id.shipping_date
else:
date_deadline = self.order_id.date_order
values = {
'group_id': group_id,
'date_planned': date_deadline,
+1 -1
View File
@@ -587,7 +587,7 @@ class PosSession(models.Model):
session_destination_id = picking_type.default_location_dest_id.id
for order in self.order_ids:
if order.company_id.anglo_saxon_accounting and order.is_invoiced or order.to_ship:
if order.company_id.anglo_saxon_accounting and order.is_invoiced or order.shipping_date:
continue
destination_id = order.partner_id.property_stock_customer.id or session_destination_id
if destination_id in lines_grouped_by_dest_location:
@@ -0,0 +1,33 @@
/** @odoo-module */
import AbstractAwaitablePopup from "@point_of_sale/js/Popups/AbstractAwaitablePopup";
import Registries from "@point_of_sale/js/Registries";
import { _lt } from "@web/core/l10n/translation";
const { onMounted, useRef, useState } = owl;
class DatePickerPopup extends AbstractAwaitablePopup {
setup() {
super.setup();
this.state = useState({shippingDate: this._today()});
this.inputRef = useRef('input');
onMounted(() => this.inputRef.el.focus());
}
getPayload() {
return this.state.shippingDate < this._today() ? this._today(): this.state.shippingDate;
}
_today() {
return new Date().toISOString().split('T')[0]
}
}
DatePickerPopup.template = 'DatePickerPopup';
DatePickerPopup.defaultProps = {
confirmText: _lt('Confirm'),
cancelText: _lt('Discard'),
title: _lt('DatePicker'),
};
Registries.Component.add(DatePickerPopup);
export default DatePickerPopup;
@@ -138,10 +138,17 @@ class PaymentScreen extends PosComponent {
this.currentOrder.set_tip(parse.float(payload));
}
}
toggleIsToShip() {
// click_ship
this.currentOrder.set_to_ship(!this.currentOrder.is_to_ship());
this.render(true);
async toggleShippingDatePicker() {
if (!this.currentOrder.getShippingDate()) {
const { confirmed, payload: shippingDate } = await this.showPopup("DatePickerPopup", {
title: this.env._t("Select the shipping date"),
});
if (confirmed) {
this.currentOrder.setShippingDate(shippingDate);
}
} else {
this.currentOrder.setShippingDate(false);
}
}
deletePaymentLine(event) {
var self = this;
@@ -326,7 +333,7 @@ class PaymentScreen extends PosComponent {
}
if (
(this.currentOrder.is_to_invoice() || this.currentOrder.is_to_ship()) &&
(this.currentOrder.is_to_invoice() || this.currentOrder.getShippingDate()) &&
!this.currentOrder.get_partner()
) {
const { confirmed } = await this.showPopup("ConfirmPopup", {
@@ -343,7 +350,7 @@ class PaymentScreen extends PosComponent {
const partner = this.currentOrder.get_partner();
if (
this.currentOrder.is_to_ship() &&
this.currentOrder.getShippingDate() &&
!(partner.name && partner.street && partner.city && partner.country_id)
) {
this.showPopup("ErrorPopup", {
@@ -29,6 +29,9 @@ class OrderReceipt extends PosComponent {
get receiptEnv() {
return this._receiptEnv;
}
get shippingDate() {
return this.receiptEnv.shippingDate
}
isSimple(line) {
return (
line.discount === 0 &&
+20 -9
View File
@@ -2496,6 +2496,7 @@ export class Order extends PosModel {
this.cashier = this.pos.get_cashier();
this.finalized = false; // if true, cannot be modified.
this.set_pricelist(this.pos.default_pricelist);
this.shippingDate = null;
this.partner = null;
@@ -2591,9 +2592,9 @@ export class Order extends PosModel {
}
this.set_partner(partner);
this.temporary = false; // FIXME
this.to_invoice = false; // FIXME
this.to_ship = false;
this.temporary = false; // FIXME
this.to_invoice = false; // FIXME
this.shippingDate = json.shipping_date;
var orderlines = json.lines;
for (var i = 0; i < orderlines.length; i++) {
@@ -2659,7 +2660,7 @@ export class Order extends PosModel {
fiscal_position_id: this.fiscal_position ? this.fiscal_position.id : false,
server_id: this.server_id ? this.server_id : false,
to_invoice: this.to_invoice ? this.to_invoice : false,
to_ship: this.to_ship ? this.to_ship : false,
shipping_date: this.shippingDate ? this.shippingDate : false,
is_tipped: this.is_tipped || false,
tip_amount: this.tip_amount || 0,
access_token: this.access_token || "",
@@ -2669,6 +2670,16 @@ export class Order extends PosModel {
}
return json;
}
_exportShippingDateForPrinting() {
const shippingDate = new Date(this.shippingDate);
const localeShippingDate = field_utils.format.date(
moment(shippingDate), {}, {timezone: false});
const exportedDate = {
localestring: localeShippingDate,
validationDate: shippingDate,
};
return exportedDate;
}
export_for_printing() {
var orderlines = [];
var self = this;
@@ -3536,6 +3547,7 @@ export class Order extends PosModel {
receipt: this.export_for_printing(),
orderlines: this.get_orderlines(),
paymentlines: this.get_paymentlines(),
shippingDate: this.shippingDate ? this._exportShippingDateForPrinting() : false,
};
}
updatePricelist(newPartner) {
@@ -3561,12 +3573,11 @@ export class Order extends PosModel {
this.set_pricelist(newPartnerPricelist);
}
/* ---- Ship later --- */
set_to_ship(to_ship) {
this.assert_editable();
this.to_ship = to_ship;
setShippingDate(shippingDate) {
this.shippingDate = shippingDate
}
is_to_ship() {
return this.to_ship;
getShippingDate() {
return this.shippingDate;
}
getHasRefundLines() {
for (const line of this.get_orderlines()) {
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="DatePickerPopup" owl="1">
<div class="popup">
<header class="title">
<t t-esc="props.title" />
</header>
<main>
<input type="date" t-model="state.shippingDate" t-ref="input" t-att-min="_today()"/>
</main>
<div class="footer footer-flex">
<div class="button confirm highlight" t-on-click="confirm">
<t t-esc="props.confirmText" />
</div>
<div class="button cancel" t-on-click="cancel">
<t t-esc="props.cancelText" />
</div>
</div>
</div>
</t>
</templates>
@@ -90,9 +90,12 @@
<i class="fa fa-archive" /> Open Cashbox
</div>
<div t-if="env.pos.config.ship_later" class="button"
t-att-class="{ highlight: currentOrder.is_to_ship() }"
t-on-click="toggleIsToShip">
t-att-class="{ highlight: currentOrder.getShippingDate() }"
t-on-click="toggleShippingDatePicker">
<i class="fa fa-clock-o" /> Ship Later
<span t-if="currentOrder.getShippingDate()">
(<t t-esc="currentOrder.getShippingDate()"/>)
<span/>
</div>
</div>
</div>
@@ -153,6 +153,19 @@
</t>
</div>
<br/>
<t t-if="shippingDate">
<div class="pos-receipt-order-data">
Expected delivery:
<t t-if="shippingDate.localestring">
<div><t t-esc="shippingDate.localestring" /></div>
</t>
<t t-else="">
<div><t t-esc="shippingDate.validationDate" /></div>
</t>
</div>
</t>
<br/>
<div class="pos-receipt-order-data">
<div><t t-esc="receipt.name" /></div>
@@ -1040,7 +1040,7 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon):
'amount_total': untax+tax,
'amount_paid': 0,
'amount_return': 0,
'to_ship': True,
'shipping_date': fields.Date.today(),
})
context_make_payment = {
@@ -86,6 +86,7 @@ class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentToOrderSc
if (confirmed) {
const currentPOSOrder = this.env.pos.get_order();
const sale_order = await this._getSaleOrder(clickedOrder.id);
clickedOrder.shipping_date = sale_order.shipping_date
try {
await this.env.pos.load_new_partners();
} catch {
@@ -293,6 +294,7 @@ class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentToOrderSc
"fiscal_position_id",
"amount_total",
"amount_untaxed",
"picking_ids",
],
],
context: this.env.session.user_context,
@@ -300,6 +302,16 @@ class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentToOrderSc
const sale_lines = await this._getSOLines(sale_order[0].order_line);
sale_order[0].order_line = sale_lines;
const picking_id = await this.rpc({
model: 'stock.picking',
method: 'read',
args: [
[sale_order[0].picking_ids[0]],
['scheduled_date'],
],
});
sale_order[0].shipping_date = picking_id[0].scheduled_date;
return sale_order[0];
}
+3
View File
@@ -33,6 +33,9 @@ const PosSaleOrderline = (Orderline) =>
this.sale_order_line_id = this.sale_order_line_id || options.sale_order_line_id;
this.down_payment_details = this.down_payment_details || options.down_payment_details;
this.customerNote = this.customerNote || options.customer_note;
if (this.sale_order_origin_id && this.sale_order_origin_id.shipping_date) {
this.order.setShippingDate(this.sale_order_origin_id.shipping_date);
}
}
init_from_JSON(json) {
super.init_from_JSON(...arguments);