[REF] point_of_sale, pos*: replace use of legacy rpc with orm service

*: l10n_co_pos, l10n_fr_pos_cert, point_of_sale, pos_loyalty,
pos_mercury, pos_restaurant, pos_sale, pos_sale_product_configurator

This is a step in the direction of making the pos no longer depend on
the legacy environment.

closes odoo/odoo#114668

Related: odoo/enterprise#37906
Signed-off-by: Trinh Jacky (trj) <trj@odoo.com>
This commit is contained in:
Samuel Degueldre
2023-03-10 11:23:51 +01:00
parent aa16405009
commit 54058db0ab
25 changed files with 294 additions and 486 deletions
@@ -2,20 +2,17 @@
import { PaymentScreen } from "@point_of_sale/js/Screens/PaymentScreen/PaymentScreen";
import { patch } from "@web/core/utils/patch";
import session from "web.session";
patch(PaymentScreen.prototype, "l10n_co_pos.PaymentScreen", {
async _postPushOrderResolve(order, order_server_ids) {
const _super = this._super;
try {
if (this.env.pos.is_colombian_country()) {
const result = await this.rpc({
model: "pos.order",
method: "search_read",
domain: [["id", "in", order_server_ids]],
fields: ["name"],
context: session.user_context,
});
const result = await this.orm.searchRead(
"pos.order",
[["id", "in", order_server_ids]],
["name"]
);
order.set_l10n_co_dian(result[0].name || false);
}
} catch {
@@ -2,20 +2,17 @@
import { PaymentScreen } from "@point_of_sale/js/Screens/PaymentScreen/PaymentScreen";
import { patch } from "@web/core/utils/patch";
import session from "web.session";
patch(PaymentScreen.prototype, "l10n_fr_pos_cert.PaymentScreen", {
async _postPushOrderResolve(order, order_server_ids) {
const _super = this._super;
try {
if (this.env.pos.is_french_country()) {
const result = await this.rpc({
model: "pos.order",
method: "search_read",
domain: [["id", "in", order_server_ids]],
fields: ["l10n_fr_hash"],
context: session.user_context,
});
const result = await this.orm.searchRead(
"pos.order",
[["id", "in", order_server_ids]],
["l10n_fr_hash"]
);
order.set_l10n_fr_hash(result[0].l10n_fr_hash || false);
}
} catch {
@@ -17,7 +17,7 @@ export class CashMovePopup extends AbstractAwaitablePopup {
super.setup();
this.notification = useService("pos_notification");
this.popup = useService("popup");
this.rpc = useService("rpc");
this.orm = useService("orm");
this.state = useState({
/** @type {'in'|'out'} */
type: "out",
@@ -55,11 +55,13 @@ export class CashMovePopup extends AbstractAwaitablePopup {
const translatedType = _t(type);
const extras = { formattedAmount, translatedType };
const reason = this.state.reason.trim();
await this.rpc({
model: "pos.session",
method: "try_cash_in_out",
args: [[this.env.pos.pos_session.id], type, amount, reason, extras],
});
await this.orm.call("pos.session", "try_cash_in_out", [
[this.env.pos.pos_session.id],
type,
amount,
reason,
extras,
]);
if (this.env.proxy.printer) {
const renderedReceipt = renderToString("point_of_sale.CashMoveReceipt", {
_receipt: {
@@ -11,18 +11,18 @@ export class SaleDetailsButton extends Component {
setup() {
super.setup(...arguments);
this.popup = useService("popup");
this.rpc = useService("rpc");
this.orm = useService("orm");
}
async onClick() {
// IMPROVEMENT: Perhaps put this logic in a parent component
// so that for unit testing, we can check if this simple
// component correctly triggers an event.
const saleDetails = await this.rpc({
model: "report.point_of_sale.report_saledetails",
method: "get_sale_details",
args: [false, false, false, [this.env.pos.pos_session.id]],
});
const saleDetails = await this.orm.call(
"report.point_of_sale.report_saledetails",
"get_sale_details",
[false, false, false, [this.env.pos.pos_session.id]]
);
const report = renderToString(
"SaleDetailsReport",
Object.assign({}, saleDetails, {
@@ -18,17 +18,17 @@ export class CashOpeningPopup extends AbstractAwaitablePopup {
openingCash: this.env.pos.pos_session.cash_register_balance_start || 0,
});
this.popup = useService("popup");
this.rpc = useService("rpc");
this.orm = useService("orm");
}
//@override
async confirm() {
this.env.pos.pos_session.cash_register_balance_start = this.state.openingCash;
this.env.pos.pos_session.state = "opened";
this.rpc({
model: "pos.session",
method: "set_cashbox_pos",
args: [this.env.pos.pos_session.id, this.state.openingCash, this.state.notes],
});
this.orm.call("pos.session", "set_cashbox_pos", [
this.env.pos.pos_session.id,
this.state.openingCash,
this.state.notes,
]);
super.confirm();
}
async openDetailsPopup() {
@@ -1,6 +1,5 @@
/** @odoo-module */
import { registry } from "@web/core/registry";
import { debounce } from "@web/core/utils/timing";
import { useService } from "@web/core/utils/hooks";
@@ -32,7 +31,7 @@ export class PartnerListScreen extends Component {
setup() {
super.setup();
this.pos = usePos();
this.rpc = useService("rpc");
this.orm = useService("orm");
this.notification = useService("pos_notification");
this.searchWordInputRef = useRef("search-word-input-partner");
@@ -157,11 +156,7 @@ export class PartnerListScreen extends Component {
this.activateEditMode();
}
async saveChanges(processedChanges) {
const partnerId = await this.rpc({
model: "res.partner",
method: "create_from_ui",
args: [processedChanges],
});
const partnerId = await this.orm.call("res.partner", "create_from_ui", [processedChanges]);
await this.env.pos.load_new_partners();
this.state.selectedPartner = this.env.pos.db.get_partner_by_id(partnerId);
this.confirm();
@@ -181,23 +176,11 @@ export class PartnerListScreen extends Component {
["parent_name", "ilike", this.state.query + "%"],
];
}
const result = await this.env.services.rpc(
{
model: "pos.session",
method: "get_pos_ui_res_partner_by_params",
args: [
[odoo.pos_session_id],
{
domain,
limit: 10,
},
],
context: this.env.session.user_context,
},
{
timeout: 3000,
shadow: true,
}
// FIXME POSREF timeout
const result = await this.orm.silent.call(
"pos.session",
"get_pos_ui_res_partner_by_params",
[[odoo.pos_session_id], { domain, limit: 10 }]
);
return result;
}
@@ -28,8 +28,8 @@ export class PaymentScreen extends Component {
setup() {
super.setup();
this.pos = usePos();
this.orm = useService("orm");
this.popup = useService("popup");
this.rpc = useService("rpc");
this.notification = useService("pos_notification");
this.payment_methods_from_config = this.env.pos.payment_methods.filter((method) =>
this.env.pos.config.payment_method_ids.includes(method.id)
@@ -34,7 +34,7 @@ export class ProductScreen extends ControlButtonsMixin(Component) {
super.setup();
this.pos = usePos();
this.popup = useService("popup");
this.rpc = useService("rpc");
this.orm = useService("orm");
this.numberBuffer = useService("number_buffer");
onMounted(this.onMounted);
// Call `reset` when the `onMounted` callback in `numberBuffer.use` is done.
@@ -126,12 +126,9 @@ export class ProductScreen extends ControlButtonsMixin(Component) {
if (!product) {
// find the barcode in the backend
let foundProductIds = [];
foundProductIds = await this.rpc({
model: "product.product",
method: "search",
args: [[["barcode", "=", code.base_code]]],
context: this.env.session.user_context,
});
foundProductIds = await this.orm.search("product.product", [
["barcode", "=", code.base_code],
]);
if (foundProductIds.length) {
await this.env.pos._addProducts(foundProductIds);
// assume that the result is unique.
@@ -16,7 +16,7 @@ export class ProductsWidgetControlPanel extends Component {
super.setup();
this.pos = usePos();
this.notification = useService("pos_notification");
this.rpc = useService("rpc");
this.orm = useService("orm");
this.updateSearch = debounce(this.updateSearch, 100);
this.state = useState({ mobileSearchBarIsShown: false });
}
@@ -63,22 +63,15 @@ export class ProductsWidgetControlPanel extends Component {
return;
}
const ProductIds = await this.rpc({
model: "product.product",
method: "search",
args: [
[
"&",
["available_in_pos", "=", true],
"|",
"|",
["name", "ilike", this.env.pos.searchProductWord],
["default_code", "ilike", this.env.pos.searchProductWord],
["barcode", "ilike", this.env.pos.searchProductWord],
],
],
context: this.env.session.user_context,
});
const ProductIds = await this.orm.search("product.product", [
"&",
["available_in_pos", "=", true],
"|",
"|",
["name", "ilike", this.env.pos.searchProductWord],
["default_code", "ilike", this.env.pos.searchProductWord],
["barcode", "ilike", this.env.pos.searchProductWord],
]);
if (ProductIds.length) {
await this.env.pos._addProducts(ProductIds, false);
}
@@ -19,7 +19,7 @@ export class ReceiptScreen extends AbstractReceiptScreen {
super.setup();
this.pos = usePos();
useErrorHandlers();
this.rpc = useService("rpc");
this.orm = useService("orm");
this.orderReceipt = useRef("order-receipt");
this.buttonMailReceipt = useRef("order-mail-receipt-button");
this.buttonPrintReceipt = useRef("order-print-receipt-button");
@@ -112,7 +112,12 @@ export class ReceiptScreen extends AbstractReceiptScreen {
if (this._shouldAutoPrint()) {
const currentOrder = this.currentOrder;
await this.printReceipt();
if (this.currentOrder && this.currentOrder === currentOrder && currentOrder._printed && this._shouldCloseImmediately()) {
if (
this.currentOrder &&
this.currentOrder === currentOrder &&
currentOrder._printed &&
this._shouldCloseImmediately()
) {
this.whenClosing();
}
}
@@ -171,11 +176,12 @@ export class ReceiptScreen extends AbstractReceiptScreen {
});
return Promise.reject();
}
await this.rpc({
model: "pos.order",
method: "action_receipt_to_customer",
args: [[order_server_id], orderName, orderPartner, ticketImage],
});
await this.orm.call("pos.order", "action_receipt_to_customer", [
[order_server_id],
orderName,
orderPartner,
ticketImage,
]);
}
}
@@ -14,7 +14,7 @@ export class InvoiceButton extends Component {
this.pos = usePos();
this.invoiceButton = useRef("invoice-button");
this.popup = useService("popup");
this.rpc = useService("rpc");
this.orm = useService("orm");
}
get isAlreadyInvoiced() {
if (!this.props.order) {
@@ -31,12 +31,12 @@ export class InvoiceButton extends Component {
}
async _downloadInvoice(orderId) {
try {
const [orderWithInvoice] = await this.rpc({
method: "read",
model: "pos.order",
args: [orderId, ["account_move"]],
kwargs: { load: false },
});
const [orderWithInvoice] = await this.orm.read(
"pos.order",
[orderId],
["account_move"],
{ load: false }
);
if (orderWithInvoice && orderWithInvoice.account_move) {
await this.env.legacyActionManager.do_action("account.account_invoices", {
additional_context: {
@@ -90,32 +90,17 @@ export class InvoiceButton extends Component {
return;
}
await this.rpc({
model: "pos.order",
method: "write",
args: [[orderId], { partner_id: newPartner.id }],
kwargs: { context: this.env.session.user_context },
});
await this.orm.write("pos.order", [orderId], { partner_id: newPartner.id });
}
const confirmed = await this.onWillInvoiceOrder(order);
if (!confirmed){
if (!confirmed) {
return;
}
// Part 2: Invoice the order.
await this.rpc(
{
model: "pos.order",
method: "action_pos_order_invoice",
args: [orderId],
kwargs: { context: this.env.session.user_context },
},
{
timeout: 30000,
shadow: true,
}
);
// FIXME POSREF timeout
await this.orm.silent.call("pos.order", "action_pos_order_invoice", [orderId]);
// Part 3: Download invoice.
await this._downloadInvoice(orderId);
@@ -42,7 +42,7 @@ export class TicketScreen extends IndependentToOrderScreen {
super.setup();
this.pos = usePos();
this.popup = useService("popup");
this.rpc = useService("rpc");
this.orm = useService("orm");
this.numberBuffer = useService("number_buffer");
this.numberBuffer.use({
triggerAtInput: (event) => this._onUpdateSelectedOrderline(event),
@@ -650,20 +650,17 @@ export class TicketScreen extends IndependentToOrderScreen {
const limit = this._state.syncedOrders.nPerPage;
const offset =
(this._state.syncedOrders.currentPage - 1) * this._state.syncedOrders.nPerPage;
const { ids, totalCount } = await this.rpc({
model: "pos.order",
method: "search_paid_order_ids",
kwargs: { config_id: this.env.pos.config.id, domain, limit, offset },
context: this.env.session.user_context,
const { ids, totalCount } = await this.orm.call("pos.order", "search_paid_order_ids", [], {
config_id: this.env.pos.config.id,
domain,
limit,
offset,
});
const idsNotInCache = ids.filter((id) => !(id in this._state.syncedOrders.cache));
if (idsNotInCache.length > 0) {
const fetchedOrders = await this.rpc({
model: "pos.order",
method: "export_for_ui",
args: [idsNotInCache],
context: this.env.session.user_context,
});
const fetchedOrders = await this.orm.call("pos.order", "export_for_ui", [
idsNotInCache,
]);
// Check for missing products and partners and load them in the PoS
await this.env.pos._loadMissingProducts(fetchedOrders);
await this.env.pos._loadMissingPartners(fetchedOrders);
+79 -125
View File
@@ -162,13 +162,10 @@ export class PosGlobalState extends PosModel {
};
}
async load_product_uom_unit() {
const params = {
model: "ir.model.data",
method: "check_object_reference",
args: ["uom", "product_uom_unit"],
};
const uom_id = await this.env.services.rpc(params);
const uom_id = await this.env.services.orm.call("ir.model.data", "check_object_reference", [
"uom",
"product_uom_unit",
]);
this.uom_unit_id = uom_id[1];
}
@@ -180,11 +177,9 @@ export class PosGlobalState extends PosModel {
}
async load_server_data() {
const loadedData = await this.env.services.rpc({
model: "pos.session",
method: "load_pos_data",
args: [[odoo.pos_session_id]],
});
const loadedData = await this.env.services.orm.call("pos.session", "load_pos_data", [
[odoo.pos_session_id],
]);
await this._processData(loadedData);
return this.after_load_server_data();
}
@@ -359,16 +354,11 @@ export class PosGlobalState extends PosModel {
search_params["limit"] = 1;
}
}
const partners = await this.env.services.rpc(
{
model: "pos.session",
method: "get_pos_ui_res_partner_by_params",
args: [[odoo.pos_session_id], search_params],
},
{
timeout: 3000,
shadow: true,
}
// FIXME POSREF TIMEOUT 3000
const partners = await this.env.services.orm.silent.call(
"pos.session",
"get_pos_ui_res_partner_by_params",
[[odoo.pos_session_id], search_params]
);
if (this.env.pos.config.partner_load_background) {
this.loadPartnersBackground(
@@ -494,27 +484,21 @@ export class PosGlobalState extends PosModel {
}
}
}
const products = await this.env.services.rpc({
model: "pos.session",
method: "get_pos_ui_product_product_by_params",
args: [odoo.pos_session_id, { domain: [["id", "in", [...missingProductIds]]] }],
});
const products = await this.env.services.orm.call(
"pos.session",
"get_pos_ui_product_product_by_params",
[odoo.pos_session_id, { domain: [["id", "in", [...missingProductIds]]] }]
);
this._loadProductProduct(products);
}
// load the partners based on the ids
async _loadPartners(partnerIds) {
if (partnerIds.length > 0) {
var domain = [["id", "in", partnerIds]];
const fetchedPartners = await this.env.services.rpc(
{
model: "pos.session",
method: "get_pos_ui_res_partner_by_params",
args: [[odoo.pos_session_id], { domain }],
},
{
timeout: 3000,
shadow: true,
}
// FIXME POSREF TIMEOUT
const fetchedPartners = await this.env.services.orm.silent.call(
"pos.session",
"get_pos_ui_res_partner_by_params",
[[odoo.pos_session_id], { domain: [["id", "in", partnerIds]] }]
);
this.addPartners(fetchedPartners);
}
@@ -536,19 +520,16 @@ export class PosGlobalState extends PosModel {
let page = 0;
let products = [];
do {
products = await this.env.services.rpc(
{
model: "pos.session",
method: "get_pos_ui_product_product_by_params",
args: [
odoo.pos_session_id,
{
offset: page * this.config.limited_products_amount,
limit: this.config.limited_products_amount,
},
],
},
{ shadow: true }
products = await this.env.services.orm.silent.call(
"pos.session",
"get_pos_ui_product_product_by_params",
[
odoo.pos_session_id,
{
offset: page * this.config.limited_products_amount,
limit: this.config.limited_products_amount,
},
]
);
this._loadProductProduct(products);
page += 1;
@@ -560,22 +541,18 @@ export class PosGlobalState extends PosModel {
let i = 0;
let partners = [];
do {
partners = await this.env.services.rpc(
{
model: "pos.session",
method: "get_pos_ui_res_partner_by_params",
args: [
[odoo.pos_session_id],
{
domain: domain,
limit: this.config.limited_partners_amount,
offset: offset + this.config.limited_partners_amount * i,
order: order,
},
],
context: this.env.session.user_context,
},
{ shadow: true }
partners = await this.env.services.orm.silent.call(
"pos.session",
"get_pos_ui_res_partner_by_params",
[
[odoo.pos_session_id],
{
order,
domain,
limit: this.config.limited_partners_amount,
offset: offset + this.config.limited_partners_amount * i,
},
]
);
this.addPartners(partners);
i += 1;
@@ -585,17 +562,11 @@ export class PosGlobalState extends PosModel {
const order = this.get_order();
// check back-end method `get_product_info_pos` to see what it returns
// We do this so it's easier to override the value returned and use it in the component template later
const productInfo = await this.env.services.rpc({
model: "product.product",
method: "get_product_info_pos",
args: [
[product.id],
product.get_price(order.pricelist, quantity),
quantity,
this.config.id,
],
kwargs: { context: this.env.session.user_context },
});
const productInfo = await this.env.services.orm.call(
"product.product",
"get_product_info_pos",
[[product.id], product.get_price(order.pricelist, quantity), quantity, this.config.id]
);
const priceWithoutTax = productInfo["all_prices"]["price_without_tax"];
const margin = priceWithoutTax - product.standard_price;
@@ -626,11 +597,11 @@ export class PosGlobalState extends PosModel {
};
}
async getClosePosInfo() {
const closingData = await this.env.services.rpc({
model: "pos.session",
method: "get_closing_control_data",
args: [[this.pos_session.id]],
});
const closingData = await this.env.services.orm.call(
"pos.session",
"get_closing_control_data",
[[this.pos_session.id]]
);
const ordersDetails = closingData.orders_details;
const paymentsAmount = closingData.payments_amount;
const payLaterAmount = closingData.pay_later_amount;
@@ -903,35 +874,22 @@ export class PosGlobalState extends PosModel {
options = options || {};
var self = this;
var timeout = typeof options.timeout === "number" ? options.timeout : 30000 * orders.length;
// Keep the order ids that are about to be sent to the
// backend. In between create_from_ui and the success callback
// new orders may have been added to it.
var order_ids_to_sync = _.pluck(orders, "id");
// we try to send the order. shadow prevents a spinner if it takes too long. (unless we are sending an invoice,
for (const order of orders) {
order.to_invoice = options.to_invoice || false;
}
// we try to send the order. silent prevents a spinner if it takes too long. (unless we are sending an invoice,
// then we want to notify the user that we are waiting on something )
var args = [
_.map(orders, function (order) {
order.to_invoice = options.to_invoice || false;
return order;
}),
];
args.push(options.draft || false);
return this.env.services
.rpc(
{
model: "pos.order",
method: "create_from_ui",
args: args,
kwargs: { context: this.env.session.user_context },
},
{
timeout: timeout,
shadow: !options.to_invoice,
}
)
const orm = options.to_invoice ? this.env.services.orm : this.env.services.orm.silent;
// FIXME POSREF timeout
// const timeout = typeof options.timeout === "number" ? options.timeout : 30000 * orders.length;
return orm
.call("pos.order", "create_from_ui", [orders, options.draft || false])
.then(function (server_ids) {
_.each(order_ids_to_sync, function (order_id) {
self.db.remove_order(order_id);
@@ -1425,27 +1383,21 @@ export class PosGlobalState extends PosModel {
*/
async _addProducts(ids, setAvailable = true) {
if (setAvailable) {
await this.env.services.rpc({
model: "product.product",
method: "write",
args: [ids, { available_in_pos: true }],
context: this.env.session.user_context,
});
await this.env.services.orm.write("product.product", ids, { available_in_pos: true });
}
const product = await this.env.services.rpc({
model: "pos.session",
method: "get_pos_ui_product_product_by_params",
args: [odoo.pos_session_id, { domain: [["id", "in", ids]] }],
});
const product = await this.env.services.orm.call(
"pos.session",
"get_pos_ui_product_product_by_params",
[odoo.pos_session_id, { domain: [["id", "in", ids]] }]
);
this._loadProductProduct(product);
}
async refreshTotalDueOfPartner(partner) {
const partnerWithUpdatedTotalDue = await this.env.services.rpc({
model: "res.partner",
method: "search_read",
fields: ["total_due"],
domain: [["id", "=", partner.id]],
});
const partnerWithUpdatedTotalDue = await this.env.services.orm.searchRead(
"res.partner",
[["id", "=", partner.id]],
["total_due"]
);
this.db.update_partners(partnerWithUpdatedTotalDue);
return partnerWithUpdatedTotalDue;
}
@@ -2896,7 +2848,9 @@ export class Order extends PosModel {
},
currency: this.pos.currency,
pos_qr_code: this._get_qr_code_data(),
ticket_code: this.pos.company.point_of_sale_ticket_unique_code ? this.ticketCode : false,
ticket_code: this.pos.company.point_of_sale_ticket_unique_code
? this.ticketCode
: false,
base_url: this.pos.base_url,
};
@@ -3745,8 +3699,8 @@ export class Order extends PosModel {
* @returns {string}
*/
_generateTicketCode() {
let code = '';
while (code.length != 5){
let code = "";
while (code.length != 5) {
code = Math.random().toString(36).slice(2, 7);
}
return code;
@@ -1,36 +0,0 @@
/** @odoo-module */
// FIXME unused module?
/**
* Many components in PoS are dependent on the PosGlobalState instance (pos).
* Therefore, for unit tests that require pos in the Components' env, we
* prepared here a test env maker (makePosTestEnv) based on
* makeTestEnvironment of web.
*/
import makeTestEnvironment from "web.test_env";
import { pos_env as env} from "@point_of_sale/js/pos_env";
import { PosGlobalState } from "@point_of_sale/js/models";
// eslint-disable-next-line no-undef
const cleanup = require("@web/../tests/helpers/cleanup");
// We override this method in the pos unit tests to prevent the unnecessary error in the web tests.
// FIXME: this is bonkers, we're overriding which method is exported by the module, this is super
// sensitive to load order. STOP DOING THIS ASAP.
cleanup.registerCleanup = () => {};
export const makePosTestEnv = env.session.is_bound
.then(() => {
const pos = new PosGlobalState({ env });
return pos.load_server_data().then(() => pos);
})
.then((pos) => {
/**
* @param {Object} env default env
* @param {Function} providedRPC mock rpc
* @param {Function} providedDoAction mock do_action
*/
return function makePosTestEnv(env = {}, providedRPC = null, providedDoAction = null) {
env = Object.assign(env, { pos });
return makeTestEnvironment(env, providedRPC);
};
});
+7 -10
View File
@@ -91,17 +91,14 @@ patch(PosStore.prototype, "pos_loyalty.PosStore", {
if (trimmedCode && trimmedCode.startsWith("044")) {
// check if the code exist in the database
// if so, use its balance, otherwise, use the unit price of the gift card product
const fetchedGiftCard = await this.globalState.env.services.rpc({
model: "loyalty.card",
method: "search_read",
args: [
[
["code", "=", trimmedCode],
["program_id", "=", program.id],
],
["points", "source_pos_order_id"],
const fetchedGiftCard = await this.orm.searchRead(
"loyalty.card",
[
["code", "=", trimmedCode],
["program_id", "=", program.id],
],
});
["points", "source_pos_order_id"]
);
// There should be maximum one gift card for a given code.
const giftCard = fetchedGiftCard[0];
if (giftCard && giftCard.source_pos_order_id) {
+18 -25
View File
@@ -1,7 +1,6 @@
/** @odoo-module **/
import { Order, Orderline, PosGlobalState } from "@point_of_sale/js/models";
import session from "web.session";
import concurrency from "web.concurrency";
import { round_decimals, round_precision } from "web.utils";
import core from "web.core";
@@ -138,16 +137,12 @@ patch(PosGlobalState.prototype, "pos_loyalty.PosGlobalState", {
* @param {int} limit Default to 1
*/
async fetchCoupons(domain, limit = 1) {
const result = await this.env.services.rpc({
model: "loyalty.card",
method: "search_read",
kwargs: {
domain: domain,
fields: ["id", "points", "code", "partner_id", "program_id"],
limit: limit,
context: session.user_context,
},
});
const result = await this.env.services.orm.searchRead(
"loyalty.card",
domain,
["id", "points", "code", "partner_id", "program_id"],
{ limit }
);
if (Object.keys(this.couponCache).length + result.length > COUPON_CACHE_MAX_SIZE) {
this.couponCache = {};
this.partnerId2CouponIds = {};
@@ -166,7 +161,8 @@ patch(PosGlobalState.prototype, "pos_loyalty.PosGlobalState", {
dbCoupon.points
);
this.couponCache[coupon.id] = coupon;
this.partnerId2CouponIds[coupon.partner_id] = this.partnerId2CouponIds[coupon.partner_id] || new Set();
this.partnerId2CouponIds[coupon.partner_id] =
this.partnerId2CouponIds[coupon.partner_id] || new Set();
this.partnerId2CouponIds[coupon.partner_id].add(coupon.id);
couponList.push(coupon);
}
@@ -196,7 +192,9 @@ patch(PosGlobalState.prototype, "pos_loyalty.PosGlobalState", {
getLoyaltyCards(partner) {
const loyaltyCards = [];
if (this.partnerId2CouponIds[partner.id]) {
this.partnerId2CouponIds[partner.id].forEach(couponId => loyaltyCards.push(this.couponCache[couponId]));
this.partnerId2CouponIds[partner.id].forEach((couponId) =>
loyaltyCards.push(this.couponCache[couponId])
);
}
return loyaltyCards;
},
@@ -214,7 +212,8 @@ patch(PosGlobalState.prototype, "pos_loyalty.PosGlobalState", {
partner.id,
points
);
this.partnerId2CouponIds[partner.id] = this.partnerId2CouponIds[partner.id] || new Set();
this.partnerId2CouponIds[partner.id] =
this.partnerId2CouponIds[partner.id] || new Set();
this.partnerId2CouponIds[partner.id].add(couponId);
}
}
@@ -1558,17 +1557,11 @@ patch(Order.prototype, "pos_loyalty.Order", {
return _t("That coupon code has already been scanned and activated.");
}
const customer = this.get_partner();
const { successful, payload } = await this.pos.env.services.rpc({
model: "pos.config",
method: "use_coupon_code",
args: [
[this.pos.config.id],
code,
this.creation_date,
customer ? customer.id : false,
],
kwargs: { context: session.user_context },
});
const { successful, payload } = await this.pos.env.services.orm.call(
"pos.config",
"use_coupon_code",
[[this.pos.config.id], code, this.creation_date, customer ? customer.id : false]
);
if (successful) {
// Allow rejecting a gift card that is not yet paid.
const program = this.pos.program_by_id[payload.program_id];
@@ -2,7 +2,6 @@
import { PaymentScreen } from "@point_of_sale/js/Screens/PaymentScreen/PaymentScreen";
import { patch } from "@web/core/utils/patch";
import session from "web.session";
import { PosLoyaltyCard } from "@pos_loyalty/js/Loyalty";
import { ErrorPopup } from "@point_of_sale/js/Popups/ErrorPopup";
@@ -36,12 +35,11 @@ patch(PaymentScreen.prototype, "pos_loyalty.PaymentScreen", {
// No need to do an rpc if no existing coupon is being used.
if (!_.isEmpty(pointChanges) || newCodes.length) {
try {
const { successful, payload } = await this.rpc({
model: "pos.order",
method: "validate_coupon_programs",
args: [[], pointChanges, newCodes],
kwargs: { context: session.user_context },
});
const { successful, payload } = await this.orm.call(
"pos.order",
"validate_coupon_programs",
[[], pointChanges, newCodes]
);
// Payload may contain the points of the concerned coupons to be updated in case of error. (So that rewards can be corrected)
if (payload && payload.updated_points) {
for (const pointChange of Object.entries(payload.updated_points)) {
@@ -124,12 +122,10 @@ patch(PaymentScreen.prototype, "pos_loyalty.PaymentScreen", {
})
);
if (!_.isEmpty(couponData)) {
const payload = await this.rpc({
model: "pos.order",
method: "confirm_coupon_programs",
args: [server_ids, couponData],
kwargs: { context: session.user_context },
});
const payload = await this.orm.call("pos.order", "confirm_coupon_programs", [
server_ids,
couponData,
]);
if (payload.coupon_updates) {
for (const couponUpdate of payload.coupon_updates) {
let dbCoupon = this.env.pos.couponCache[couponUpdate.old_id];
@@ -252,17 +252,9 @@ patch(PaymentScreen.prototype, "pos_mercury.PaymentScreen", {
message: this.env._t("Handling transaction..."),
});
}
this.rpc(
{
model: "pos_mercury.mercury_transaction",
method: "do_payment",
args: [transaction],
},
{
timeout: self.server_timeout_in_ms,
}
)
// FIXME POSREF timeout
this.orm
.call("pos_mercury.mercury_transaction", "do_payment", [transaction])
.then(function (data) {
// if not receiving a response from Vantiv, we should retry
if (data === "timeout") {
@@ -457,17 +449,9 @@ patch(PaymentScreen.prototype, "pos_mercury.PaymentScreen", {
message: message,
});
}
this.rpc(
{
model: "pos_mercury.mercury_transaction",
method: rpc_method,
args: [request_data],
},
{
timeout: self.server_timeout_in_ms,
}
)
// FIXME POSREF timeout
this.orm
.call("pos_mercury.mercury_transaction", rpc_method, [request_data])
.then(function (data) {
if (data === "timeout") {
self.retry_mercury_transaction(def, null, retry_nr, true, self.do_reversal, [
@@ -25,7 +25,7 @@ export class FloorScreen extends Component {
super.setup();
this.pos = usePos();
this.popup = useService("popup");
this.rpc = useService("rpc");
this.orm = useService("orm");
const floor = this.props.floor ? this.props.floor : this.env.pos.floors[0];
this.state = useState({
selectedFloorId: floor.id,
@@ -78,7 +78,7 @@ export class FloorScreen extends Component {
this.state.selectedTableId = null;
}
async _createTableHelper(copyTable) {
let existingTable = this.activeFloor.tables;
const existingTable = this.activeFloor.tables;
let newTable;
if (copyTable) {
newTable = Object.assign({}, copyTable);
@@ -88,11 +88,11 @@ export class FloorScreen extends Component {
let posV = 0;
let posH = 10;
const referenceScreenWidth = 1180;
const spaceBetweenTable = 15 * (screen.width/referenceScreenWidth);
const spaceBetweenTable = 15 * (screen.width / referenceScreenWidth);
const h_min = spaceBetweenTable;
const h_max = screen.width;
const v_max = screen.height;
let potentialWidth = 100 * (h_max/referenceScreenWidth);
let potentialWidth = 100 * (h_max / referenceScreenWidth);
if (potentialWidth > 130) {
potentialWidth = 130;
} else if (potentialWidth < 75) {
@@ -100,11 +100,16 @@ export class FloorScreen extends Component {
}
const heightTable = potentialWidth;
const widthTable = potentialWidth;
let positionTable = [];
const positionTable = [];
existingTable.forEach((table) => {
positionTable.push([table.position_v, table.position_v + table.height, table.position_h, table.position_h + table.width])
})
positionTable.push([
table.position_v,
table.position_v + table.height,
table.position_h,
table.position_h + table.width,
]);
});
positionTable.sort((tableA, tableB) => {
if (tableA[0] < tableB[0]) {
@@ -118,18 +123,25 @@ export class FloorScreen extends Component {
}
});
let actualHeight = 100
let actualHeight = 100;
let impossible = true;
while(actualHeight <= (v_max - heightTable - spaceBetweenTable) && impossible) {
let tableIntervals = [[h_min, h_min, v_max], [h_max, h_max, v_max]];
while (actualHeight <= v_max - heightTable - spaceBetweenTable && impossible) {
const tableIntervals = [
[h_min, h_min, v_max],
[h_max, h_max, v_max],
];
for (let i = 0; i < positionTable.length; i++) {
if (positionTable[i][0] >= (actualHeight + heightTable + spaceBetweenTable)) {
if (positionTable[i][0] >= actualHeight + heightTable + spaceBetweenTable) {
continue;
} else if ((positionTable[i][1] + spaceBetweenTable) <= actualHeight) {
} else if (positionTable[i][1] + spaceBetweenTable <= actualHeight) {
continue;
} else {
tableIntervals.push([positionTable[i][2], positionTable[i][3], positionTable[i][1]]);
tableIntervals.push([
positionTable[i][2],
positionTable[i][3],
positionTable[i][1],
]);
}
}
@@ -151,7 +163,10 @@ export class FloorScreen extends Component {
nextHeight = tableIntervals[i][2];
}
if (tableIntervals[i+1][0] - tableIntervals[i][1] > widthTable + spaceBetweenTable) {
if (
tableIntervals[i + 1][0] - tableIntervals[i][1] >
widthTable + spaceBetweenTable
) {
impossible = false;
posV = actualHeight;
posH = tableIntervals[i][1] + spaceBetweenTable;
@@ -201,11 +216,7 @@ export class FloorScreen extends Component {
async _save(table) {
const tableCopy = { ...table };
delete tableCopy.floor;
const tableId = await this.rpc({
model: "restaurant.table",
method: "create_from_ui",
args: [tableCopy],
});
const tableId = await this.orm.call("restaurant.table", "create_from_ui", [tableCopy]);
table.id = tableId;
this.env.pos.tables_by_id[tableId] = table;
}
@@ -213,11 +224,9 @@ export class FloorScreen extends Component {
if (this.state.isEditMode) {
return;
}
const result = await this.rpc({
model: "pos.config",
method: "get_tables_order_count",
args: [this.env.pos.config.id],
});
const result = await this.orm.call("pos.config", "get_tables_order_count", [
this.env.pos.config.id,
]);
result.forEach((table) => {
const table_obj = this.env.pos.tables_by_id[table.id];
const unsynced_orders = this.env.pos.getTableOrders(table_obj.id).filter(
@@ -366,10 +375,8 @@ export class FloorScreen extends Component {
async setFloorColor(color) {
this.state.floorBackground = color;
this.activeFloor.background_color = color;
await this.rpc({
model: "restaurant.floor",
method: "write",
args: [[this.activeFloor.id], { background_color: color }],
await this.orm.write("restaurant.floor", [this.activeFloor.id], {
background_color: color,
});
}
async deleteTable() {
@@ -385,11 +392,9 @@ export class FloorScreen extends Component {
}
const originalSelectedTableId = this.state.selectedTableId;
this.env.pos.tables_by_id[originalSelectedTableId].active = false;
await this.rpc({
model: "restaurant.table",
method: "create_from_ui",
args: [{ active: false, id: originalSelectedTableId }],
});
await this.orm.call("restaurant.table", "create_from_ui", [
{ active: false, id: originalSelectedTableId },
]);
this.activeFloor.tables = this.activeTables.filter(
(table) => table.id !== originalSelectedTableId
);
@@ -108,11 +108,7 @@ patch(TicketScreen.prototype, "pos_restaurant.TicketScreen", {
order.set_tip(amount);
order.finalized = true;
const tip_line = order.selected_orderline;
await this.rpc({
method: "set_tip",
model: "pos.order",
args: [serverId, tip_line.export_as_JSON()],
});
await this.orm.call("pos.order", "set_tip", [serverId, tip_line.export_as_JSON()]);
}
if (order === this.env.pos.get_order()) {
this._selectNextOrder(order);
@@ -128,11 +124,7 @@ patch(TicketScreen.prototype, "pos_restaurant.TicketScreen", {
}
},
async setNoTip(serverId) {
await this.rpc({
method: "set_no_tip",
model: "pos.order",
args: [serverId],
});
await this.orm.call("set_no_tip", "pos.order", [serverId]);
},
_getOrderStates() {
const result = this._super(...arguments);
@@ -17,7 +17,7 @@ export class TipScreen extends Component {
this.pos = usePos();
this.posReceiptContainer = useRef("pos-receipt-container");
this.popup = useService("popup");
this.rpc = useService("rpc");
this.orm = useService("orm");
this.state = this.currentOrder.uiState.TipScreen;
this._totalAmount = this.currentOrder.get_total_with_tax();
@@ -61,11 +61,7 @@ export class TipScreen extends Component {
}
if (!amount) {
await this.rpc({
method: "set_no_tip",
model: "pos.order",
args: [serverId],
});
await this.orm.call("set_no_tip", "pos.order", [serverId]);
this.goNextScreen();
return;
}
@@ -95,11 +91,7 @@ export class TipScreen extends Component {
// set_tip calls add_product which sets the new line as the selected_orderline
const tip_line = order.selected_orderline;
await this.rpc({
method: "set_tip",
model: "pos.order",
args: [serverId, tip_line.export_as_JSON()],
});
await this.orm.call("pos.order", "set_tip", [serverId, tip_line.export_as_JSON()]);
this.goNextScreen();
}
goNextScreen() {
+12 -22
View File
@@ -7,7 +7,7 @@ import { Printer } from "@point_of_sale/js/printers";
import { patch } from "@web/core/utils/patch";
const QWeb = core.qweb;
const TIMEOUT = 7500;
// const TIMEOUT = 7500;
patch(PosGlobalState.prototype, "pos_restaurant.PosGlobalState", {
setup() {
@@ -112,16 +112,11 @@ patch(PosGlobalState.prototype, "pos_restaurant.PosGlobalState", {
async _getTableOrdersFromServer(tableIds) {
this.set_synch("connecting", 1);
try {
const orders = await this.env.services.rpc(
{
model: "pos.order",
method: "get_table_draft_orders",
args: [tableIds],
},
{
timeout: TIMEOUT,
shadow: true,
}
// FIXME POSREF timeout
const orders = await this.env.services.orm.silent.call(
"pos.order",
"get_table_draft_orders",
[tableIds]
);
this.set_synch("connected");
return orders;
@@ -170,19 +165,14 @@ patch(PosGlobalState.prototype, "pos_restaurant.PosGlobalState", {
return;
}
const timeout = TIMEOUT * removedOrdersIds.length;
this.set_synch("connecting", removedOrdersIds.length);
try {
const removeOrdersResponseData = await this.env.services.rpc(
{
model: "pos.order",
method: "remove_from_ui",
args: [removedOrdersIds],
},
{
timeout: timeout,
shadow: true,
}
// FIXME POSREF timeout
// const timeout = TIMEOUT * removedOrdersIds.length;
const removeOrdersResponseData = await this.env.services.orm.silent.call(
"pos.order",
"remove_from_ui",
[removedOrdersIds]
);
this.set_synch("connected");
this._postRemoveFromServer(removedOrdersIds, removeOrdersResponseData);
@@ -25,7 +25,7 @@ export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentTo
setup() {
super.setup();
this.popup = useService("popup");
this.rpc = useService("rpc");
this.orm = useService("orm");
this.root = useRef("root");
this.numberBuffer = useService("number_buffer");
this.saleOrderFetcher = useService("sale_order_fetcher");
@@ -288,44 +288,37 @@ export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentTo
}
async _getSaleOrder(id) {
const sale_order = await this.rpc({
model: "sale.order",
method: "read",
args: [
[id],
[
"order_line",
"partner_id",
"pricelist_id",
"fiscal_position_id",
"amount_total",
"amount_untaxed",
"picking_ids",
],
],
context: this.env.session.user_context,
});
const [sale_order] = await this.orm.read(
"sale.order",
[id],
[
"order_line",
"partner_id",
"pricelist_id",
"fiscal_position_id",
"amount_total",
"amount_untaxed",
"picking_ids",
]
);
const sale_lines = await this._getSOLines(sale_order[0].order_line);
sale_order[0].order_line = sale_lines;
const sale_lines = await this._getSOLines(sale_order.order_line);
sale_order.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;
if (sale_order.picking_ids[0]) {
const [picking] = await this.orm.read(
"stock.picking",
[sale_order.picking_ids[0]],
["scheduled_date"]
);
sale_order.shipping_date = picking.scheduled_date;
}
return sale_order[0];
return sale_order;
}
async _getSOLines(ids) {
const so_lines = await this.rpc({
model: "sale.order.line",
method: "read_converted",
args: [ids],
context: this.env.session.user_context,
});
const so_lines = await this.orm.call("sale.order.line", "read_converted", [ids]);
return so_lines;
}
}
@@ -10,21 +10,12 @@ export class SetSaleOrderButton extends Component {
setup() {
super.setup();
this.pos = usePos();
this.rpc = useService("rpc");
}
get currentOrder() {
return this.env.pos.get_order();
this.orm = useService("orm");
}
async click() {
// ping the server, if no error, show the screen
// Use rpc from services which resolves even when this
// component is destroyed (removed together with the popup).
await this.env.services.rpc({
model: "sale.order",
method: "browse",
args: [[]],
kwargs: { context: this.env.session.user_context },
});
// FIXME POSREF why are we calling browse for a ping?
// Why don't we let the order management screen deal with the offline error?
await this.orm.call("sale.order", "browse", [[]]);
const screen = this.env.isMobile
? "MobileSaleOrderManagementScreen"
: "SaleOrderManagementScreen";
@@ -12,11 +12,11 @@ patch(Order.prototype, "pos_sale_product_configurator.Order", {
// The `optional_product_ids` only contains ids of the product templates and not the product itself
// We don't load all the product template in the pos, so it'll be hard to know if the id comes from
// a product available in POS. We send a quick cal to the back end to verify.
const isProductLoaded = await this.pos.env.services.rpc({
model: "product.product",
method: "has_optional_product_in_pos",
args: [[product.id]],
});
const isProductLoaded = await this.pos.env.services.orm.call(
"product.product",
"has_optional_product_in_pos",
[[product.id]]
);
if (isProductLoaded) {
const quantity = this.get_selected_orderline().get_quantity();
const info = await this.pos.getProductInfo(product, quantity);