chore: import enterprise addons 19.0 bulk snapshot

This commit is contained in:
1b-agent committed 2026-09-16 10:13:08 +00:00
commit ca4af030d3
39951 files changed
+15570005

No files matched your search

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="l10n_at_pos.ClosingReceipts">
<div class="pos-receipt p-2 h-auto">
<!-- receipt header -->
<img t-attf-src="/web/image?model=res.company&amp;id={{config.company_id.id}}&amp;field=logo" alt="Logo" class="pos-receipt-logo"/>
<br/>
<div class="d-flex flex-column align-items-center">
<div class="pos-receipt-contact">
<!-- contact address -->
<div t-if="config.company_id.partner_id?.[1]" t-esc="config.company_id.partner_id[1]" />
<t t-if="config.company_id.phone">
<div>Tel:<t t-esc="config.company_id.phone" /></div>
</t>
<t t-if="config.company_id.vat">
<div><t t-esc="config.company_id.country_id?.vat_label || 'Tax ID'"/>: <t t-esc="config.company_id.vat" /></div>
</t>
<div t-if="config.company_id.email" t-esc="config.company_id.email" />
<div t-if="config.company_id.website" t-esc="config.company_id.website" />
<div class="pos-receipt-title fs-1 my-3">
Closing Receipt of <t t-esc="heading"/>
</div>
<div t-if="data.signature_creation_unit_id" style="white-space:pre-line">
SCU id: <t t-esc="data.signature_creation_unit_id"/>
</div>
<div t-if="data.receipt_number" style="white-space:pre-line">
Receipt Number: <t t-esc="data.receipt_number"/>
</div>
</div>
</div>
<br/>
<t t-foreach="raw_data" t-as="key" t-key="key">
<div class="line-details fs-2 d-flex justify-content-between">
<div class="product-name d-inline-block flex-grow-1 fw-bolder pe-1 text-truncate">
<span class="qty px-1 fw-bolder me-1"/>
<span class="text-wrap" t-esc="mappedName[key]"/>
</div>
<div t-esc="raw_data[key]" class="product-price price fw-bolder"/>
</div>
</t>
<br />
<div class="text-center">
<img t-att-src="qrImage" class="w-75"/>
</div>
<div class="text-center fs-3">
<p>Powered by Odoo</p>
</div>
</div>
</t>
</templates>
@@ -0,0 +1,40 @@
import { Component, useState } from "@odoo/owl";
import { _t } from "@web/core/l10n/translation";
import { Dialog } from "@web/core/dialog/dialog";
export class DateSelectionPopup extends Component {
static template = "l10n_at_pos.DateSelectionPopup";
static components = { Dialog };
static props = {
title: { type: String, optional: true },
confirmLabel: { type: String, optional: true },
getPayload: Function,
close: Function,
};
static defaultProps = {
confirmLabel: _t("Print"),
title: _t("DatePicker"),
};
setup() {
this.state = useState({
period: "monthly",
selectedDate: this.defaultDate(),
});
}
defaultDate() {
const currentDate = new Date();
const year = currentDate.getFullYear();
const month = currentDate.getMonth(); // 0-based index (0 = January)
const lastMonthYear = month === 0 ? year - 1 : year;
const lastMonth = month % 12; // month will be already 1 index less
return `${lastMonthYear}-${String(lastMonth).padStart(2, "0")}`;
}
confirm() {
this.props.getPayload({
selectedDate: this.state.selectedDate,
period: this.state.period,
});
this.props.close();
}
}
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="l10n_at_pos.DateSelectionPopup">
<Dialog title="props.title" size="'md'">
<label class="form-check-label me-5 mb-3">
<input type="radio" class="form-check-input" value="monthly" t-model="state.period"/>
Monthly
</label>
<label class="form-check-label">
<input type="radio" class="form-check-input" value="yearly" t-model="state.period"/>
Yearly
</label>
<input class="form-control form-control-lg mx-auto" type="month" t-model="state.selectedDate" t-ref="input"/>
<t t-set-slot="footer">
<button class="btn btn-lg btn-primary" t-on-click="confirm" t-esc="props.confirmLabel"/>
</t>
</Dialog>
</t>
</templates>
@@ -0,0 +1,8 @@
import { PosStore } from "@point_of_sale/app/services/pos_store";
import { patch } from "@web/core/utils/patch";
patch(PosStore.prototype, {
canEditPayment(order) {
return this.company.l10n_at_is_fon_authenticated ? false : super.canEditPayment(order);
},
});
@@ -0,0 +1,19 @@
import OrderPaymentValidation from "@point_of_sale/app/utils/order_payment_validation";
import { patch } from "@web/core/utils/patch";
patch(OrderPaymentValidation.prototype, {
async afterOrderValidation() {
if (this.pos.config.company_id.l10n_at_is_fon_authenticated) {
const [signed, receipt_number, qr_data] = await this.pos.data.call(
"pos.order",
"sign_order_receipt",
[this.pos.selectedOrder.id]
);
// updating values after signing receipt for the selected order
this.pos.selectedOrder.is_fiskaly_order_receipt_signed = signed;
this.pos.selectedOrder.l10n_at_pos_order_receipt_qr_data = qr_data;
this.pos.selectedOrder.l10n_at_pos_order_receipt_number = receipt_number;
}
await super.afterOrderValidation(...arguments);
},
});
@@ -0,0 +1,77 @@
import { patch } from "@web/core/utils/patch";
import { _t } from "@web/core/l10n/translation";
import { renderToElement } from "@web/core/utils/render";
import { AlertDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
import { Navbar } from "@point_of_sale/app/components/navbar/navbar";
import { DateSelectionPopup } from "@l10n_at_pos/app/components/popup/date_selection_popup/date_selection_popup";
patch(Navbar.prototype, {
setup() {
super.setup(...arguments);
this.mapNames = {
gross_amount_standard: _t("Gross Amount Standard"),
gross_amount_reduced_1: _t("Gross Amount Reduced 1"),
gross_amount_reduced_2: _t("Gross Amount Reduced 2"),
gross_amount_special: _t("Gross Amount Special"),
gross_amount_zero: _t("Gross Amount Zero"),
};
},
get menuLabel() {
return _t("Monthly / Yearly Receipts");
},
printClosingReceipts() {
this.dialog.add(DateSelectionPopup, {
title: _t("Print closing receipts"),
getPayload: async (payload) => {
const res = await this.pos.data.call(
"pos.config",
"fetch_fiskaly_closing_receipt_data",
[[this.pos.session.config_id.id], payload.selectedDate, payload.period]
);
if (res["data"].length && this.pos.hardwareProxy) {
// prepare title based on selection
const data = res["data"][0];
const date = new Date(`${payload.selectedDate}-01`);
const monthName = date.toLocaleString("default", { month: "long" });
const year = date.getFullYear();
const title = payload.period == "monthly" ? `${monthName} ${year}` : `${year}`;
// prepare qrImage data
const codeWriter = new window.ZXing.BrowserQRCodeSvgWriter();
const qr_code_svg = new XMLSerializer().serializeToString(
codeWriter.write(data["qr_code_data"], 150, 150)
);
const qrImage = "data:image/svg+xml;base64," + window.btoa(qr_code_svg);
const receipt = renderToElement("l10n_at_pos.ClosingReceipts", {
config: this.pos.session.config_id,
heading: title,
data: data,
qrImage: qrImage,
raw_data: data["schema"]["raw"],
mappedName: this.mapNames,
});
const { successful, message } =
await this.pos.hardwareProxy.printer.printReceipt(receipt);
if (!successful) {
this.dialog.add(AlertDialog, { title: message.title, body: message.body });
}
} else {
if (res["message"] !== "success") {
return this.dialog.add(AlertDialog, {
title: _t("No data found!"),
body: res["message"],
});
}
// Message success means we got the data still here only means no printer connected
this.dialog.add(AlertDialog, {
title: _t("Printing Error"),
body: _t("No printer connected to print the receipt"),
});
}
},
});
},
});
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="l10n_at_pos.Navbar" t-inherit="point_of_sale.Navbar" t-inherit-mode="extension">
<xpath expr="//Dropdown//div[hasclass('pos-burger-menu-items')]" position="inside">
<DropdownItem t-if="pos.company.l10n_at_is_fon_authenticated" onSelected="() => this.printClosingReceipts()">
<t t-esc="menuLabel"/>
</DropdownItem>
</xpath>
</t>
</templates>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="l10n_at_pos.OrderReceipt" t-inherit="point_of_sale.OrderReceipt" t-inherit-mode="extension">
<xpath expr="//div[hasclass('before-footer')]" position="inside">
<div t-if="order.l10n_at_pos_order_receipt_qr_data" class="d-flex justify-content-center">
<img t-attf-src="data:image/png;base64,{{order.l10n_at_pos_order_receipt_qr_data}}" alt="QR Code" class="w-50"/>
</div>
</xpath>
</t>
</templates>
@@ -0,0 +1,11 @@
<templates id="template" xml:space="preserve">
<t t-name="l10n_in_pos.ReceiptHeader" t-inherit="point_of_sale.ReceiptHeader" t-inherit-mode="extension">
<xpath expr="//div[hasclass('pos-receipt-contact')]" position="inside">
<div class="pos-receipt-center-align">
<div t-if="order.config.l10n_at_cash_regid">Fiskaly Register ID: <t t-esc="order.config.l10n_at_cash_regid"/></div>
<div t-if="order.l10n_at_pos_order_receipt_number">Fiskaly Receipt No: <t t-esc="order.l10n_at_pos_order_receipt_number"/></div>
<div t-translation="off" t-if="order.config.l10n_at_cash_regid and !order.is_fiskaly_order_receipt_signed" class="fw-bolder">Sicherheitseinrichtung ausgefallen</div>
</div>
</xpath>
</t>
</templates>
@@ -0,0 +1,6 @@
import { PosConfig } from "@point_of_sale/../tests/unit/data/pos_config.data";
PosConfig._records = PosConfig._records.map((record) => ({
...record,
company_id: 252,
}));
@@ -0,0 +1,34 @@
import { patch } from "@web/core/utils/patch";
import { ResCompany } from "@point_of_sale/../tests/unit/data/res_company.data";
patch(ResCompany.prototype, {
_load_pos_data_fields() {
return [...super._load_pos_data_fields(), "l10n_at_is_fon_authenticated"];
},
});
ResCompany._records = [
...ResCompany._records,
{
id: 252,
currency_id: 125,
email: false,
website: false,
company_registry: false,
vat: false,
name: "My AT Company",
phone: "",
partner_id: 1,
country_id: 12,
state_id: false,
tax_calculation_rounding_method: "round_per_line",
point_of_sale_use_ticket_qr_code: true,
point_of_sale_ticket_unique_code: false,
point_of_sale_ticket_portal_url_display_mode: "qr_code_and_url",
street: "",
city: "",
zip: "",
account_fiscal_country_id: 12,
l10n_at_is_fon_authenticated: true,
},
];
@@ -0,0 +1,11 @@
import { ResCountry } from "@point_of_sale/../tests/unit/data/res_country.data";
ResCountry._records = [
...ResCountry._records,
{
id: 12,
name: "Austria",
code: "AT",
vat_label: "USt",
},
];
@@ -0,0 +1,15 @@
import { test, expect } from "@odoo/hoot";
import { setupPosEnv } from "@point_of_sale/../tests/unit/utils";
import { definePosModels } from "@point_of_sale/../tests/unit/data/generate_model_definitions";
definePosModels();
test("canEditPayment", async () => {
const store = await setupPosEnv();
const company = store.config.company_id;
store.addNewOrder();
const order = store.getOrder();
expect(store.canEditPayment(order)).toBe(false);
company.l10n_at_is_fon_authenticated = false;
expect(store.canEditPayment(order)).toBe(true);
});