Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions product_weighing/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

================
Product Weighing
================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:21fbf5e2cf7c9407d15e8a541c5b18e4abfda1788eb91e37fcc51ebd66e5d553
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-qrtl%2Frmm--custom-lightgray.png?logo=github
:target: https://github.com/qrtl/rmm-custom/tree/15.0/product_weighing
:alt: qrtl/rmm-custom

|badge1| |badge2| |badge3|

This module adds an **append-only** weighing line model
(``product.weighing.line``) that stores weighing results (gross weight,
dust deduction and net weight) sent from an external system against a
product.

To support the "no tampering of weighing data" claim, weighing lines are
create-only: creation is allowed only for the dedicated integration
group, and the model overrides ``write`` and ``unlink`` to always raise,
so a line can never be modified or deleted after creation through any
path - UI, RPC, ``sudo`` or the developer-mode superuser included
(direct SQL is out of scope by design). The parent product cannot be
deleted either while lines exist (``ondelete="restrict"``), so the trail
is preserved.

The product form gets a read-only **Weighing** tab showing three
aggregate fields (computed from the lines) and the list of weighing
lines.

**Table of contents**

.. contents::
:local:

Configuration
=============

Assign the API integration user to the **Weighing Integration** group.
Only members of this group can createweighing lines; no group can edit
or delete them.

The three aggregate fields on the product (Total Net Weight, Weighing
Count, Weighing Confirmed At) are computed from the weighing lines, so
the integration only needs to create ``product.weighing.line`` records;
it does not write to ``product.template``.

Usage
=====

Open a product and go to the **Weighing** tab. The tab shows the
aggregate values and the weighing lines. Lines cannot be added, edited
or removed from the interface; click a line to open its read-only detail
(including the image hash).

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/qrtl/rmm-custom/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/qrtl/rmm-custom/issues/new?body=module:%20product_weighing%0Aversion:%2015.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
-------

* Quartile

Maintainers
-----------

This module is part of the `qrtl/rmm-custom <https://github.com/qrtl/rmm-custom/tree/15.0/product_weighing>`_ project on GitHub.

You are welcome to contribute.
1 change: 1 addition & 0 deletions product_weighing/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
18 changes: 18 additions & 0 deletions product_weighing/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2026 Quartile (https://www.quartile.co)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
"name": "Product Weighing",
"summary": "Append-only weighing lines linked to products for tamper-proof records",
"category": "Product",
"version": "15.0.1.0.0",
"author": "Quartile",
"website": "https://www.quartile.co",
"license": "AGPL-3",
"depends": ["product"],
"data": [
"security/product_weighing_security.xml",
"security/ir.model.access.csv",
"views/product_template_views.xml",
],
"installable": True,
}
203 changes: 203 additions & 0 deletions product_weighing/i18n/ja.po
Comment thread
nobuQuartile marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * product_weighing
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 15.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-05 05:05+0000\n"
"PO-Revision-Date: 2026-08-05 05:05+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: product_weighing
#: model:ir.model.constraint,message:product_weighing.constraint_product_weighing_line_weighing_id_uniq
msgid "A weighing line with this Weighing ID already exists."
msgstr "この計量IDの計量明細は既に存在します。"

#. module: product_weighing
#: model:ir.model.fields,help:product_weighing.field_product_weighing_line__dust_detail
msgid "Breakdown of deducted items (e.g. 'cage cart x2, cart x1')."
msgstr "控除品目の内訳(例:「かご台車×2, 台車×1」)。"

#. module: product_weighing
#: model:ir.model.fields,field_description:product_weighing.field_product_weighing_line__company_id
msgid "Company"
msgstr "会社"

#. module: product_weighing
#: model:ir.model.fields,field_description:product_weighing.field_product_weighing_line__create_uid
msgid "Created by"
msgstr "作成者"

#. module: product_weighing
#: model:ir.model.fields,field_description:product_weighing.field_product_weighing_line__create_date
msgid "Created on"
msgstr "作成日"

#. module: product_weighing
#: model:ir.model.fields,field_description:product_weighing.field_product_weighing_line__display_name
msgid "Display Name"
msgstr "表示名"

#. module: product_weighing
#: model:ir.model.fields,field_description:product_weighing.field_product_weighing_line__dust_detail
msgid "Dust Deduction Detail"
msgstr "ダスト控除内訳"

#. module: product_weighing
#: model:ir.model.fields,field_description:product_weighing.field_product_weighing_line__dust_weight
msgid "Dust Deduction Weight (kg)"
msgstr "ダスト控除重量(kg)"

#. module: product_weighing
#: model:ir.model.fields,help:product_weighing.field_product_weighing_line__weighing_id
msgid "External weighing identifier (e.g. WEIGH-KNG-20260513-0001)."
msgstr "外部計量ID(例: WEIGH-KNG-20260513-0001)。"

#. module: product_weighing
#: model:ir.model.fields,field_description:product_weighing.field_product_weighing_line__gross_weight
msgid "Gross Weight (kg)"
msgstr "総重量(kg)"

#. module: product_weighing
#: model:ir.model.fields,field_description:product_weighing.field_product_weighing_line__id
msgid "ID"
msgstr "ID"

#. module: product_weighing
#: model:ir.model.fields,field_description:product_weighing.field_product_weighing_line__image_hash
msgid "Image Hash"
msgstr "画像ハッシュ"

#. module: product_weighing
#: model:ir.model.fields,field_description:product_weighing.field_product_weighing_line____last_update
msgid "Last Modified on"
msgstr "最終更新日"

#. module: product_weighing
#: model:ir.model.fields,field_description:product_weighing.field_product_weighing_line__write_uid
msgid "Last Updated by"
msgstr "最終更新者"

#. module: product_weighing
#: model:ir.model.fields,field_description:product_weighing.field_product_weighing_line__write_date
msgid "Last Updated on"
msgstr "最終更新日"

#. module: product_weighing
#: model:ir.model.fields,field_description:product_weighing.field_product_weighing_line__measured_at
msgid "Measured At"
msgstr "計測日時"

#. module: product_weighing
#: model:ir.model.fields,field_description:product_weighing.field_product_weighing_line__measurer_name
msgid "Measurer"
msgstr "計測者"

#. module: product_weighing
#: model:ir.model.fields,field_description:product_weighing.field_product_weighing_line__net_weight
msgid "Net Weight (kg)"
msgstr "正味重量(kg)"

#. module: product_weighing
#: model:ir.model.fields,field_description:product_weighing.field_product_weighing_line__product_tmpl_id
msgid "Product"
msgstr "プロダクト"

#. module: product_weighing
#: model:ir.model,name:product_weighing.model_product_template
msgid "Product Template"
msgstr "プロダクトテンプレート"

#. module: product_weighing
#: model:ir.model.fields,field_description:product_weighing.field_product_weighing_line__receipt_no
msgid "Receipt No."
msgstr "レシート番号"

#. module: product_weighing
#: model:ir.model.fields,help:product_weighing.field_product_weighing_line__image_hash
msgid ""
"SHA-256 of the evidence image(s), comma-separated, for tamper verification."
msgstr "証跡画像のSHA-256(複数の場合はカンマ区切り)。改ざん検証用。"

#. module: product_weighing
#: model:ir.model.fields,field_description:product_weighing.field_product_product__total_net_weight
#: model:ir.model.fields,field_description:product_weighing.field_product_template__total_net_weight
msgid "Total Net Weight"
msgstr "合計正味重量"

#. module: product_weighing
#: model:res.groups,comment:product_weighing.group_weighing_integration
msgid ""
"Users allowed to create weighing lines via the\n"
" external integration (odoo-upload-system)."
msgstr "外部連携(odoo-upload-system)経由で計量明細を作成できるユーザ。"

#. module: product_weighing
#: model_terms:ir.ui.view,arch_db:product_weighing.product_template_view_form
msgid "Weighing"
msgstr "計量"

#. module: product_weighing
#: model:ir.model.fields,field_description:product_weighing.field_product_product__weighing_confirmed_at
#: model:ir.model.fields,field_description:product_weighing.field_product_template__weighing_confirmed_at
msgid "Weighing Confirmed At"
msgstr "計量確定日時"

#. module: product_weighing
#: model:ir.model.fields,field_description:product_weighing.field_product_product__weighing_count
#: model:ir.model.fields,field_description:product_weighing.field_product_template__weighing_count
msgid "Weighing Count"
msgstr "計量数"

#. module: product_weighing
#: model:ir.model.fields,field_description:product_weighing.field_product_weighing_line__weighing_id
msgid "Weighing ID"
msgstr "計量ID"

#. module: product_weighing
#: model:res.groups,name:product_weighing.group_weighing_integration
msgid "Weighing Integration"
msgstr "計量連携"

#. module: product_weighing
#: model:ir.model,name:product_weighing.model_product_weighing_line
msgid "Weighing Line"
msgstr "計量明細"

#. module: product_weighing
#: model:ir.model.fields,field_description:product_weighing.field_product_product__weighing_line_ids
#: model:ir.model.fields,field_description:product_weighing.field_product_template__weighing_line_ids
msgid "Weighing Lines"
msgstr "計量明細"

#. module: product_weighing
#: code:addons/product_weighing/models/product_weighing_line.py:0
#, python-format
msgid "Weighing lines are append-only and cannot be deleted."
msgstr "計量明細は追記専用のため削除できません。"

#. module: product_weighing
#: code:addons/product_weighing/models/product_weighing_line.py:0
#, python-format
msgid "Weighing lines are append-only and cannot be modified."
msgstr "計量明細は追記専用のため変更できません。"

#. module: product_weighing
#: model:ir.model.fields,help:product_weighing.field_product_product__weighing_confirmed_at
#: model:ir.model.fields,help:product_weighing.field_product_template__weighing_confirmed_at
msgid ""
"When the most recent weighing line was recorded in Odoo, i.e. the latest "
"creation timestamp among the lines. This is the time the external system "
"pushed the result, not the time the weighing itself took place - for that, "
"see Measured At on the individual lines. The two differ whenever results are"
" backfilled after an outage."
msgstr ""
"最新の計量明細がOdooに記録された日時、すなわち明細の作成日時のうち最も新しいものです。これは外部システムが結果を送信した日時であり、計量そのものが行われた"
"日時ではありません。後者については各明細の計測日時を参照してください。障害発生後に結果を遡って登録した場合、両者は異なります。"
2 changes: 2 additions & 0 deletions product_weighing/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import product_weighing_line
from . import product_template
44 changes: 44 additions & 0 deletions product_weighing/models/product_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Copyright 2026 Quartile (https://www.quartile.co)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import api, fields, models


class ProductTemplate(models.Model):
_inherit = "product.template"

weighing_line_ids = fields.One2many(
"product.weighing.line",
"product_tmpl_id",
string="Weighing Lines",
)
weighing_count = fields.Integer(
compute="_compute_weighing_aggregates",
store=True,
)
total_net_weight = fields.Float(
digits=(10, 2),
compute="_compute_weighing_aggregates",
store=True,
)
weighing_confirmed_at = fields.Datetime(
compute="_compute_weighing_aggregates",
store=True,
help="When the most recent weighing line was recorded in Odoo, i.e. the "
"latest creation timestamp among the lines. This is the time the "
"external system pushed the result, not the time the weighing itself "
"took place - for that, see Measured At on the individual lines. The "
"two differ whenever results are backfilled after an outage.",
)

@api.depends(
"weighing_line_ids",
"weighing_line_ids.net_weight",
"weighing_line_ids.create_date",
)
def _compute_weighing_aggregates(self):
for tmpl in self:
lines = tmpl.weighing_line_ids
tmpl.weighing_count = len(lines)
tmpl.total_net_weight = sum(lines.mapped("net_weight"))
tmpl.weighing_confirmed_at = max(lines.mapped("create_date"), default=False)
Loading
Loading