fix -ve stock issue

This commit is contained in:
Raman Marikanti 2025-12-12 12:15:57 +05:30
parent c9949af167
commit 5e595e9f2b
6 changed files with 247 additions and 6 deletions

View File

@ -1,2 +1,3 @@
from . import mrp
from . import sale_order_line
from . import sale_order_line
from . import stock_quant

View File

@ -4,8 +4,8 @@ from ast import literal_eval
from collections import defaultdict
from odoo import fields, models, _, api
from odoo.tools import float_round
from odoo.exceptions import ValidationError
from odoo.tools import float_round, float_compare
from odoo.exceptions import ValidationError, UserError
class MrpProduction(models.Model):

View File

@ -68,11 +68,19 @@ class SaleOrderLine(models.Model):
digits='Product Price', store=True, readonly=False, precompute=True,
groups="base.group_user")
@api.depends('product_id', 'company_id', 'product_uom','product_uom_qty')
price_unit_kg = fields.Float(string="Rate(kg)")
@api.depends('product_uom_qty')
def _compute_bag_weight(self):
for line in self:
line.bag_weight = line.product_id.weight * line.product_uom_qty
@api.onchange('bag_weight')
def _onchange_bag_update_qty(self):
for line in self:
if line.product_id and line.product_id.weight:
line.product_uom_qty = line.bag_weight / line.product_id.weight
@api.depends('product_id', 'company_id', 'currency_id', 'product_uom')
def _compute_purchase_price(self):
@ -100,4 +108,19 @@ class SaleOrderLine(models.Model):
if line.order_id and line.order_id.state == 'sale':
continue
line.price_unit = 0.0
# @api.onchange('price_unit', 'price_unit_kg', 'bag_weight')
# def _onchange_prices(self):
# for line in self:
# if not line.bag_weight:
# line.price_unit_kg = 0.0
# return
#
# # If price_unit is changed by user → update price_unit_kg
# if line.price_unit and not self._origin.price_unit == line.price_unit:
# line.price_unit_kg = line.price_unit / line.bag_weight
#
# # If price_unit_kg is changed by user → update price_unit
# elif line.price_unit_kg and not self._origin.price_unit_kg == line.price_unit_kg:
# line.price_unit = line.price_unit_kg * line.bag_weight

View File

@ -0,0 +1,39 @@
from odoo import fields, models, _, api
from odoo.tools import float_round, float_compare
from odoo.exceptions import ValidationError, UserError
class StockQuant(models.Model):
_inherit = "stock.quant"
@api.constrains("product_id", "quantity")
def check_negative_qty(self):
if self.env.context.get("skip_negative_qty_check"):
return
p = self.env["decimal.precision"].precision_get("Product Unit of Measure")
for quant in self:
if (
float_compare(quant.quantity, 0, precision_digits=p) == -1
and quant.product_id.type == "consu"
and quant.location_id.usage in ["internal", "transit"]
):
msg_add = ""
if quant.lot_id:
msg_add = _(" lot {}").format(quant.lot_id.name_get()[0][1])
raise ValidationError(
_(
"You cannot validate this stock operation because the "
"stock level of the product '{name}'{name_lot} would "
"become negative "
"({q_quantity}) on the stock location '{complete_name}' "
"and negative stock is "
"not allowed for this product and/or location."
).format(
name=quant.product_id.display_name,
name_lot=msg_add,
q_quantity=quant.quantity,
complete_name=quant.location_id.complete_name,
)
)

View File

@ -0,0 +1,176 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="samashti_tax_invoice_report">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="o">
<t t-set="company" t-value="o.env.company"/>
<t t-call="costing_mrp_bom.samashti_tax_invoice_report_custom" />
</t>
</t>
</template>
<template id="samashti_tax_invoice_report_custom">
<t t-call="web.external_layout_striped">
<div class="page-border" style="border:1px solid #000; padding:15px; margin-bottom:20px; font-family: Arial, sans-serif; font-size:12px;">
<div style="text-align:center; border-bottom:1px solid #000; padding-bottom:5px; margin-bottom:10px;">
<h4><strong>Tax Invoice: </strong><t t-esc="o.name"/> </h4>
</div>
<div class="row" style="font-size:12px">
<div style="margin:3px;" class="col-4">
<strong style="font-size:14px;">Customer Info</strong><br/>
<t t-esc="o.partner_id.contact_address"/><br/>
<strong>GSTIN:</strong> <t t-esc="o.partner_id.vat"/> <br/>
<strong>State:</strong> <t t-esc="o.partner_id.state_id.name"/>
</div>
<div style="margin:3px;" class="col-4">
<strong style="font-size:14px">Shipping Info</strong><br/>
<t t-esc="o.partner_shipping_id.contact_address"/><br/>
<strong>GSTIN:</strong> <t t-esc="o.partner_shipping_id.vat"/> <br/>
<strong>State:</strong> <t t-esc="o.partner_shipping_id.state_id.name"/>
</div>
<div style="margin:3px;" class="col-4">
<strong>Invoice No:</strong> <t t-esc="o.name"/><br/>
<strong>Date:</strong> <t t-esc="o.invoice_date"/><br/>
<strong>Terms and Conditions:</strong><t t-esc="o.narration"/>
</div>
</div>
<!-- Product / Item Table -->
<div style="min-height:400px; height:auto;">
<table style="width:100%; font-size:12px; border-collapse:collapse;">
<thead>
<tr style="border-bottom:1px solid #000;">
<th style="border:1px solid #000; padding:5px;">S.No</th>
<th style="border:1px solid #000; padding:5px;">Description</th>
<th style="border:1px solid #000; padding:5px;">HSN/SAC</th>
<th style="border:1px solid #000; padding:5px;">GST Rate</th>
<th style="border:1px solid #000; padding:5px;">Qty</th>
<th style="border:1px solid #000; padding:5px;">Rate</th>
<th style="border:1px solid #000; padding:5px;">Amount</th>
</tr>
</thead>
<tbody>
<t t-set="n" t-value="0"/>
<t t-foreach="o.invoice_line_ids" t-as="line">
<t t-set="n" t-value="n+1"/>
<tr>
<td style="border:1px solid #000; padding:5px; text-align:center;"><t t-esc="n"/></td>
<td style="border:1px solid #000; padding:5px;"><t t-esc="line.name"/></td>
<td style="border:1px solid #000; padding:5px; text-align:center;"><t t-esc="line.product_id.l10n_in_hsn_code"/></td>
<td style="border:1px solid:#000; padding:5px; text-align:center;"><t t-esc="line.tax_ids.name"/></td>
<td style="border:1px solid:#000; padding:5px; text-align:right;"><t t-esc="line.quantity"/></td>
<td style="border:1px solid:#000; padding:5px; text-align:right;"><t t-esc="line.price_unit"/></td>
<td style="border:1px solid:#000; padding:5px; text-align:right;"><t t-esc="line.price_subtotal"/></td>
</tr>
</t>
</tbody>
</table>
</div>
<!-- Totals & Tax-->
<div style="width:100%; margin-top:10px; font-size:13px;text-align:right;">
<strong style="text-align:right; padding-right:10px;">Subtotal: </strong><t style="text-align:right; width:100px;" t-esc="o.amount_untaxed"/><br/>
<strong style="text-align:right; padding-right:10px;">Tax: </strong><t style="text-align:right; width:100px;" t-esc="o.amount_tax"/><br/>
<strong style="text-align:right; padding-right:10px;">Total: </strong><t style="text-align:right; width:100px;" t-esc="o.amount_total"/>
</div>
<!-- Footer / Terms -->
<div style="margin-top:15px; font-size:12px; border-top:1px solid #000; padding-top:5px;">
<div class="mb-2" style="text-align:left;">
<p class="text-end lh-sm" t-if="o.company_id.display_invoice_amount_total_words" style="text-align:left;">
Total amount in words: <br/>
<small class="text-dark lh-sm"><span style="text-align:left;" t-field="o.amount_total_words"></span></small>
</p>
</div>
<t t-if="o.company_id.account_fiscal_country_id.code == 'IN'">
<t t-set="hsn_summary" t-value="o._l10n_in_get_hsn_summary_table()"/>
<t t-if="hsn_summary">
<div name="l10n_in_hsn_summary" class="mt-3" style="page-break-inside: avoid;">
<h5>HSN Summary</h5>
<table class="table table-sm table-borderless col-6">
<thead>
<th>HSN/SAC</th>
<th class="text-end">Quantity</th>
<th class="text-end">Rate %</th>
<th class="text-end">Taxable Value</th>
<th class="text-end" t-if="hsn_summary['has_gst']">SGST</th>
<th class="text-end" t-if="hsn_summary['has_gst']">CGST</th>
<th class="text-end" t-if="hsn_summary['has_igst']">IGST</th>
<th class="text-end" t-if="hsn_summary['has_cess']">CESS</th>
</thead>
<tr t-foreach="hsn_summary['items']" t-as="item">
<td t-esc="item['l10n_in_hsn_code']"/>
<td class="text-end">
<span t-esc="item['quantity']"/>
<span t-if="hsn_summary['display_uom']">(<t t-esc="item['uom_name']"/>)</span>
</td>
<td class="text-end" t-esc="item['rate']"/>
<td class="text-end">
<span t-esc="item['amount_untaxed']" t-options="{'widget': 'monetary', 'display_currency': o.currency_id}"/>
</td>
<td class="text-end" t-if="hsn_summary['has_gst']">
<span t-esc="item['tax_amount_sgst']" t-options="{'widget': 'monetary', 'display_currency': o.currency_id}"/>
</td>
<td class="text-end" t-if="hsn_summary['has_gst']">
<span t-esc="item['tax_amount_cgst']" t-options="{'widget': 'monetary', 'display_currency': o.currency_id}"/>
</td>
<td class="text-end" t-if="hsn_summary['has_igst']">
<span t-esc="item['tax_amount_igst']" t-options="{'widget': 'monetary', 'display_currency': o.currency_id}"/>
</td>
<td class="text-end" t-if="hsn_summary['has_cess']">
<span t-esc="item['tax_amount_cess']" t-options="{'widget': 'monetary', 'display_currency': o.currency_id}"/>
</td>
</tr>
</table>
</div>
</t>
</t>
</div>
<t t-name="custom_invoice_bank_details">
<div class="footer-section">
<table style="width:100%; border-collapse: collapse;">
<!-- Bank Details -->
<tr>
<td style="padding: 5px; vertical-align: top; width: 30%;"><strong>Bank Details:</strong></td>
<td style="padding: 5px; vertical-align: top;">
Bank Name: <span t-field="o.company_id.bank_ids[0].bank_id.name"/><br/>
Account No: <span t-field="o.company_id.bank_ids[0].acc_number"/><br/>
IFSC: <span t-field="o.company_id.bank_ids[0].bank_id.bic"/>
</td>
</tr>
<!-- Declaration -->
<tr>
<td style="padding: 5px; vertical-align: top;"><strong>Declaration:</strong></td>
<td style="padding: 5px; vertical-align: top;">
Goods once sold will not be taken back. All disputes are subject to jurisdiction XYZ.
</td>
</tr>
<!-- Authorised Signatory -->
<tr>
<td style="padding: 5px; vertical-align: top;"><strong>Authorised Signatory:</strong></td>
<td style="padding: 5px; vertical-align: top;">
______________________________ <br/>
<span>Name &amp; Designation</span>
</td>
</tr>
</table>
</div>
</t>
</div>
</t>
</template>
</odoo>

View File

@ -21,9 +21,11 @@
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='order_line']/list//field[@name='price_unit']" position="after">
<xpath expr="//field[@name='order_line']/list//field[@name='price_unit']" position="replace">
<field name="price_unit" string="Rate(bags)"/>
<!-- <field name="price_unit_kg" string="Rate(kg)"/>-->
<field name="purchase_price" groups="base.group_user" force_save="1" readonly="1"/>
<field name="bag_weight" groups="base.group_user"/>
<field name="bag_weight" groups="base.group_user" sum="Total"/>
</xpath>
<xpath expr="//field[@name='tax_totals']" position="before">
<div class="d-flex float-end" colspan="2" groups="base.group_user">