19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:32:12 +01:00
parent 79f83631d5
commit 73afc09215
6267 changed files with 1534193 additions and 1130106 deletions

View file

@ -0,0 +1,40 @@
import { patch } from "@web/core/utils/patch";
import { ForecastedDetails } from "@stock/stock_forecasted/forecasted_details";
patch(ForecastedDetails.prototype, {
_freeStockCondition(line){
return super._freeStockCondition(line) && line?.removal_date != -1;
},
_prepareLines() {
if (this.props.docs.use_expiration_date) {
this.props.docs.lines.sort((a, b) => (a.removal_date || 0) - (b.removal_date || 0));
}
super._prepareLines();
},
_prepareData(){
// Whenever there's a Free Stock line without an expiration date,
// remove the quantities "to remove" from this line to improve readibility
super._prepareData();
for (const productId of this.productIds){
if (!(productId in this.FreeStockLinesPerProduct)){
continue;
}
const lines = this.FreeStockLinesPerProduct[productId]
let noRemovalDateLine = lines.find(line => !line.removal_date);
let withRemovalDateLines = lines.filter(line => line.removal_date);
if (noRemovalDateLine && withRemovalDateLines.length) {
const sumQty = withRemovalDateLines.reduce((sum, line) => sum + (line.quantity || 0), 0);
noRemovalDateLine.quantity = noRemovalDateLine.quantity - sumQty;
}
if (noRemovalDateLine && noRemovalDateLine?.quantity === 0 && withRemovalDateLines?.length){
const removeIndex = this.lines.indexOf(noRemovalDateLine);
this.lines.splice(removeIndex,1);
}
}
},
_sameLineRule(line, nextLine){
const res = super._sameLineRule(line, nextLine);
const FreeStock = this.FreeStockLinesPerProduct[line.product.id] || [];
return res || (FreeStock.includes(line) && FreeStock.includes(nextLine));
}
});

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="product_expiry.ForecastedDetails" t-inherit="stock.ForecastedDetails" t-inherit-mode="extension">
<xpath expr="//t[@name='freeStock_cell']" position="before">
<t name="expiredStock_cell" t-elif="line?.removal_date === -1">
<span class='text-warning'>Expired Stock</span>
</t>
</xpath>
<xpath expr="//td[@name='quantity_cell']" position="attributes">
<attribute name="t-attf-class">#{line?.removal_date == -1 and 'text-warning'}</attribute>
</xpath>
<xpath expr="//td[@name='usedby_cell']" position="inside">
<t t-if="line.removal_date">
<t t-if="line.removal_date === -1">
<span class="text-warning">To remove now</span>
</t>
<t t-else="">
<span class="text-muted">To remove on <t t-out="line.removal_date"/></span>
</t>
</t>
</xpath>
</t>
</templates>

View file

@ -0,0 +1,8 @@
import { patch } from "@web/core/utils/patch";
import { ForecastedHeader } from "@stock/stock_forecasted/forecasted_header";
patch(ForecastedHeader.prototype, {
get to_remove_qty() {
return Object.values(this.props.docs.product).reduce((sum, p) => sum + (p.to_remove_qty || 0), 0);
}
});

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="product_expiry.ForecastedHeader" t-inherit="stock.ForecastedHeader" t-inherit-mode="extension">
<xpath expr="//div[@name='on_hand']" position="after">
<t t-if="props.docs.use_expiration_date">
<div class="h3 col-md-auto text-center">-</div>
<div t-attf-class="col-md-auto text-center #{to_remove_qty}">
<div class="h3">
<t t-out="_formatFloat(to_remove_qty)"/>
</div>
<div>To Remove</div>
</div>
</t>
</xpath>
</t>
</templates>

View file

@ -0,0 +1,45 @@
import { registry } from "@web/core/registry";
registry.category("web_tour.tours").add('test_generate_serial_with_expiration', {
steps: () => [
{
trigger: "button:contains('Details')",
run: "click",
},
{
trigger: '.o_widget_generate_serials > button',
run: "click",
},
{
trigger: ".modal .btn-primary:contains('New')",
run: "click",
},
{
trigger: ".modal .btn-primary:contains('Generate')",
run: "click",
},
// Check that the expiration date is now set after generating Serials/Lots.
{
trigger: "td.o_field_cell[name=expiration_date]",
run: () => {
const exp_dates = document.querySelectorAll("td.o_field_cell[name=expiration_date]");
for (const exp_date of exp_dates) {
if (exp_date.innerText.trim() !== "Jun 3, 2020, 12:00 AM") {
throw new Error("Expiration date should be Jun 3, 12:00 AM.");
}
}
}
},
{
trigger: ".modal button:contains(save)",
run: "click",
},
{
trigger: "button.o_form_button_save",
run: "click",
},
{
trigger: ".o_form_saved",
},
],
});