From f75fd84af08b15d50ffde7d134e2b1630d448d48 Mon Sep 17 00:00:00 2001 From: "admin.suherdy" Date: Thu, 20 Nov 2025 20:49:42 +0700 Subject: [PATCH] first commit --- __init__.py | 1 + __manifest__.py | 16 ++ __pycache__/__init__.cpython-310.pyc | Bin 0 -> 221 bytes models/__init__.py | 1 + models/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 239 bytes .../account_move_line.cpython-310.pyc | Bin 0 -> 4410 bytes models/account_move_line.py | 147 ++++++++++++++++++ views/account_move_views.xml | 32 ++++ 8 files changed, 197 insertions(+) create mode 100644 __init__.py create mode 100644 __manifest__.py create mode 100644 __pycache__/__init__.cpython-310.pyc create mode 100644 models/__init__.py create mode 100644 models/__pycache__/__init__.cpython-310.pyc create mode 100644 models/__pycache__/account_move_line.cpython-310.pyc create mode 100644 models/account_move_line.py create mode 100644 views/account_move_views.xml diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..9a7e03e --- /dev/null +++ b/__init__.py @@ -0,0 +1 @@ +from . import models \ No newline at end of file diff --git a/__manifest__.py b/__manifest__.py new file mode 100644 index 0000000..bfc01eb --- /dev/null +++ b/__manifest__.py @@ -0,0 +1,16 @@ +{ + "name": "Vendor Bill Price Edit", + "version": "17.0.1.0.0", + "summary": "Allow editing vendor bill tax-exclusive and tax-inclusive amounts with automatic price unit recomputation.", + "license": "GPL-3", + "author": "Suherdy Yacob", + "category": "Accounting", + "depends": [ + "account" + ], + "data": [ + "views/account_move_views.xml" + ], + "application": False, + "installable": True +} \ No newline at end of file diff --git a/__pycache__/__init__.cpython-310.pyc b/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..19e4a0fcf25e864b0ca3247a1268ff4f6b140609 GIT binary patch literal 221 zcmYk0zY4-I5XO`G2N4P#+?~5LIJt=Q2}E#n2{9LFAjy@a75YdnK2TRDU%|<%lONpo z@g3ap!#rOz(sQx38_L&I{*_UwX;MK347g*SUpZ%xU06ALb6S^tTzUlK(y7cw7N?sB zi*t&feUxa>8Q_;X}r~5wJKB^D+}U0bPWbgKLi5eZZCA7I`j$vLlSor0HeHF h=VTkLHqwCYgp@YePRgns#?^rcdS{LkP?`t|_5}}fIT!!{ literal 0 HcmV?d00001 diff --git a/models/__init__.py b/models/__init__.py new file mode 100644 index 0000000..cb78dd3 --- /dev/null +++ b/models/__init__.py @@ -0,0 +1 @@ +from . import account_move_line \ No newline at end of file diff --git a/models/__pycache__/__init__.cpython-310.pyc b/models/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ec5ef63d236f53c28bb1ad24f783f539a3dde86b GIT binary patch literal 239 zcmYjLF=_)b5R}d_n1I1~f$M8dq)HQvUl0QB(k!xe;RKTQkaUK7QXY|yT((y^F7s`lVc>q$o&3c+*m3{ ti^!>%3nkY1gq%I!{`f6=M8o?lv_G%QyJd<`mKB6c+c=t{50Oxu(ns{XZ9Iy^0SY$ZMNJ{nmK6B@p+}0<>#@W3$pQXx0?=={BF7# zejX*^)~TRWbo$VAVyLA1)o>+G^B|TDznk_4!#wm=J-c^D&UA-Dgh_YgN4#xGJIh6s ztVw6mP+D1@3fK@~z|$li$@*ajGmq>?d{EQYoGP1+eAvzZiCL*jor%^**&ilRe!%4E zfe5=%7Nsx&4|DR$#cU%Q_?uzEQ{k^faqJHS#_>ZQWNV=D)qau%7nAg>1MU3O?$Lf^NF9*bfFl(&?t1h%bCG%GcAR zi$GXNd756kzR(?Fy8fSc4E^7AQ~z%3z2~6a`5qQufFVIq!4RB6@Y4n!BvVrF89jmxTWXu4 zg75MSp*~1P{vpOAF5aXsDjx7fTt-bfwG?goIPb&f$DnZ7{cU{Bbci{&b@heiyrNT= zI!qs$mW!WS!|zcz3Z*@^uZB8RCNY{$dgbY9J6US))fIEP`mMvhg?qT;lr}to)Pn8{zu9j z;zf~MX&n(kF-Ku4ojiDmh{zBoAuX5vp*fAlt){q3CVvaRbc;OB6KuN|dpV1((@K*7e3blGRv z!Cixx`7z!I3YW9Tdam#4y9A*ILF$Pvn%u%cZ?l#$6B>jI&{Z2EShTM&nF{) z$=TRR?&dD6RS3wi_UTU*Ki7V9 zd0Z`K3h$i8>*!M}Y{0mttkp5YdSTAPvKsj@@(~k%ENWwiX^BVQHcatn)V=!xat6}j zjiDy~LTzBj!Pp2qgv6<>zkM0zLy@$C))7Qeq=bX)(aP7uR*Ab-35<^CwIhs>9yZA|N80Qw;tUVX91Nvq5~-wAf6I@a8{Z8Ri}FkmA3S}A=L888(ulx_ z39`>1c0m%mRu4o*IK$4eT|x_p479@vwrkRvK+JI+STW9n;&P+Vw;9L>JwRrM^|rYr zehiD^eG(r)fX8o8`7qvb(p$-J;PY03EG!vXETV<9ln)PV75yrd#m}fGv4i+2iQ6P7 zM1|t`+BDjfE5Cp~y8!WGur^)SaGxPy@4hl%kI+$4!-R|`ptu>Q-5}0xAvGU6tF2)$ zJpZ~qDQJsJPic1Tsv=26jp{5R-hx)pDOr3(g4j^}gv2jMT!)ZGKX@oD5hQD2yHPS? z?ZhNX7u=+_Q>ug`ai{>~#IHzwMtSr(W}GQkwl)m2Og3=1Q7rA3rlq+at*uKVP9I3- zV-7gUxRW*V($l}B87g;QKIG8XI*VqQ-GXp!4-{&$(|Q%MuG^s0SvIGiZh%ttI%`5} zva0%@%cnea}Qbn*8x8X`e7MV6h*Q+ft3ok>D?ip*p&4od@wmTQ9^t^k! zS6a1t;OF(5f~?&~8e1>NgS6 zbk|87t@LoYf_zUmvW!l5F44PQp2bMo-= 0 else -1 + + def compute_total(base_price): + if taxes: + res = taxes.compute_all( + base_price, + quantity=qty, + currency=currency, + product=self.product_id, + partner=partner, + is_refund=self.is_refund, + ) + value = res["total_included" if target_key == "total_included" else "total_excluded"] + else: + value = base_price * qty + return abs(value) + + if float_is_zero(target_abs, precision_rounding=currency.rounding or 0.01): + base_after_discount = 0.0 + else: + price_guess = abs(self.price_unit * discount_factor) + per_unit_target = target_abs / max(qty, 1.0) + high = max(price_guess * 2.0, per_unit_target * 2.0, 1.0) + low = 0.0 + base_after_discount = None + for _ in range(40): + mid = (low + high) / 2.0 + computed = compute_total(sign * mid) + if abs(computed - target_abs) <= (currency.rounding or 0.01): + base_after_discount = mid + break + if computed > target_abs: + high = mid + else: + low = mid + if base_after_discount is None: + base_after_discount = mid + + return (sign * base_after_discount) / discount_factor + + def _apply_manual_price_edit(self, field_name): + self.ensure_one() + if not self._is_vendor_bill_price_editable_line(): + return + + currency = self._get_price_edit_currency() + target_key = "total_excluded" if field_name == "price_subtotal" else "total_included" + target_value = self[field_name] + current_amount = self._compute_amount_from_current_price_unit(target_key) + if currency.compare_amounts(target_value, current_amount) == 0: + return + + new_price_unit = self._compute_price_unit_from_target_amount(target_value, target_key) + if new_price_unit is False: + return + self.with_context(skip_vendor_bill_price_edit=True).price_unit = new_price_unit + + # ------------------------------------------------------------------------- + # Onchanges + # ------------------------------------------------------------------------- + + @api.onchange("price_subtotal") + def _onchange_vendor_bill_price_subtotal(self): + for line in self: + line._apply_manual_price_edit("price_subtotal") + + @api.onchange("price_total") + def _onchange_vendor_bill_price_total(self): + for line in self: + line._apply_manual_price_edit("price_total") \ No newline at end of file diff --git a/views/account_move_views.xml b/views/account_move_views.xml new file mode 100644 index 0000000..d061355 --- /dev/null +++ b/views/account_move_views.xml @@ -0,0 +1,32 @@ + + + + + account.move.form.vendor.bill.price.edit + account.move + + + + + { + 'default_move_type': context.get('default_move_type'), + 'journal_id': journal_id, + 'default_partner_id': commercial_partner_id, + 'default_currency_id': currency_id or company_currency_id, + 'default_display_type': 'product', + 'quick_encoding_vals': quick_encoding_vals, + 'vendor_bill_price_edit': True + } + + + + {'readonly': ['|', ('parent.state', '!=', 'draft'), ('parent.move_type', 'not in', ('in_invoice', 'in_refund'))]} + + + False + {'readonly': ['|', ('parent.state', '!=', 'draft'), ('parent.move_type', 'not in', ('in_invoice', 'in_refund'))]} + + + + + \ No newline at end of file