mirror of
https://github.com/inventree/InvenTree.git
synced 2025-07-01 03:00:54 +00:00
Bug fix for purchase order pricing (#4373)
* Account for pack size when calculating purchase_price for received line items * Clearer display of "unit pricing" when part has units * Add data migration to fix historical pricing bugs * Remove debug statement
This commit is contained in:
79
InvenTree/stock/migrations/0094_auto_20230220_0025.py
Normal file
79
InvenTree/stock/migrations/0094_auto_20230220_0025.py
Normal file
@ -0,0 +1,79 @@
|
||||
# Generated by Django 3.2.18 on 2023-02-20 00:25
|
||||
|
||||
import logging
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
logger = logging.getLogger('inventree')
|
||||
|
||||
|
||||
def fix_purchase_price(apps, schema_editor):
|
||||
"""Data migration for fixing historical issue with StockItem.purchase_price field.
|
||||
|
||||
Ref: https://github.com/inventree/InvenTree/pull/4373
|
||||
|
||||
Due to an existing bug, if a PurchaseOrderLineItem was received,
|
||||
which had:
|
||||
|
||||
a) A SupplierPart with a non-unity pack size
|
||||
b) A defined purchase_price
|
||||
|
||||
then the StockItem.purchase_price was not calculated correctly!
|
||||
|
||||
Specifically, the purchase_price was not divided through by the pack_size attribute.
|
||||
|
||||
This migration fixes this by looking through all stock items which:
|
||||
|
||||
- Is linked to a purchase order
|
||||
- Have a purchase_price field
|
||||
- Are linked to a supplier_part
|
||||
- We can determine correctly that the calculation was misapplied
|
||||
"""
|
||||
|
||||
StockItem = apps.get_model('stock', 'stockitem')
|
||||
|
||||
items = StockItem.objects.exclude(
|
||||
purchase_order=None
|
||||
).exclude(
|
||||
supplier_part=None
|
||||
).exclude(
|
||||
purchase_price=None
|
||||
).exclude(
|
||||
supplier_part__pack_size=1
|
||||
)
|
||||
|
||||
n_updated = 0
|
||||
|
||||
for item in items:
|
||||
# Grab a reference to the associated PurchaseOrder
|
||||
# Trying to find an absolute match between this StockItem and an associated PurchaseOrderLineItem
|
||||
po = item.purchase_order
|
||||
for line in po.lines.all():
|
||||
# SupplierPart match
|
||||
if line.part == item.supplier_part:
|
||||
# Unit price matches original PurchaseOrder (and is thus incorrect)
|
||||
if item.purchase_price == line.purchase_price:
|
||||
item.purchase_price /= item.supplier_part.pack_size
|
||||
item.save()
|
||||
|
||||
n_updated += 1
|
||||
|
||||
if n_updated > 0:
|
||||
logger.info(f"Corrected purchase_price field for {n_updated} stock items.")
|
||||
|
||||
|
||||
def reverse(apps, schema_editor): # pragmae: no cover
|
||||
pass
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('stock', '0093_auto_20230217_2140'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(
|
||||
fix_purchase_price,
|
||||
reverse_code=reverse,
|
||||
)
|
||||
]
|
@ -187,7 +187,10 @@
|
||||
<tr>
|
||||
<td><span class='fas fa-dollar-sign'></span></td>
|
||||
<td>{% trans "Purchase Price" %}</td>
|
||||
<td>{% include "price_data.html" with price=item.purchase_price %}</td>
|
||||
<td>
|
||||
{% include "price_data.html" with price=item.purchase_price %}
|
||||
{% if item.part.units %} / {{ item.part.units }}{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if item.parent %}
|
||||
|
Reference in New Issue
Block a user