File: stock.py

package info (click to toggle)
tryton-modules-account-stock-anglo-saxon 5.0.2-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, sid
  • size: 412 kB
  • sloc: python: 526; xml: 171; makefile: 6; sh: 3
file content (179 lines) | stat: -rw-r--r-- 6,658 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# This file is part of Tryton.  The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from decimal import Decimal
from trytond.model import fields, Check
from trytond.pool import Pool, PoolMeta
from trytond.transaction import Transaction

__all__ = ['Move']


def _get_field(type_):
    if type_.startswith('in_'):
        return 'in_anglo_saxon_quantity'
    else:
        return 'out_anglo_saxon_quantity'


class Move(metaclass=PoolMeta):
    __name__ = 'stock.move'
    in_anglo_saxon_quantity = fields.Float('Input Anglo-Saxon Quantity',
        required=True)
    out_anglo_saxon_quantity = fields.Float('Output Anglo-Saxon Quantity',
        required=True)

    @classmethod
    def __setup__(cls):
        super(Move, cls).__setup__()
        cls._allow_modify_closed_period.update(['in_anglo_saxon_quantity',
                'out_anglo_saxon_quantity'])

        t = cls.__table__()
        cls._sql_constraints += [
            ('check_in_anglo_saxon_quantity',
                Check(t, t.quantity >= t.in_anglo_saxon_quantity),
                'Anglo-Saxon quantity can not be greater than quantity.'),
            ('check_out_anglo_saxon_quantity',
                Check(t, t.quantity >= t.out_anglo_saxon_quantity),
                'Anglo-Saxon quantity can not be greater than quantity.'),
            ]

    @staticmethod
    def default_in_anglo_saxon_quantity():
        return 0.0

    @staticmethod
    def default_out_anglo_saxon_quantity():
        return 0.0

    def _get_account_stock_move_lines(self, type_):
        pool = Pool()
        Uom = pool.get('product.uom')
        AccountMoveLine = pool.get('account.move.line')
        Currency = pool.get('currency.currency')
        lines = super(Move, self)._get_account_stock_move_lines(type_)
        if (type_.endswith('supplier')
                and self.product.cost_price_method == 'fixed'):
            cost_price = Uom.compute_price(self.product.default_uom,
                self.cost_price, self.uom)
            with Transaction().set_context(date=self.effective_date):
                unit_price = Currency.compute(self.currency, self.unit_price,
                    self.company.currency, round=False)
            amount = self.company.currency.round(
                Decimal(str(self.quantity)) * (unit_price - cost_price))
            if self.company.currency.is_zero(amount):
                return lines
            account = self.product.account_stock_supplier_used
            for move_line in lines:
                if move_line.account == account:
                    break
            else:
                return lines
            if type_.startswith('in_'):
                move_line.credit += amount
                debit = amount
                credit = Decimal(0)
            else:
                move_line.debit += amount
                debit = Decimal(0)
                credit = amount
            if amount < Decimal(0):
                debit, credit = -credit, -debit
            move_line = AccountMoveLine(
                debit=debit,
                credit=credit,
                account=self.product.account_expense_used,
                )
            lines.append(move_line)
        return lines

    @classmethod
    def _get_anglo_saxon_move(cls, moves, quantity, type_):
        '''
        Generator of (move, qty, cost_price) where move is the move to be
        consumed, qty is the quantity (in the product default uom) to be
        consumed on this move and cost_price is in the company currency.
        '''
        pool = Pool()
        Uom = pool.get('product.uom')
        Currency = pool.get('currency.currency')

        as_qty_field = _get_field(type_)

        consumed_qty = 0.0
        for move in moves:
            qty = Uom.compute_qty(move.uom,
                    move.quantity - getattr(move, as_qty_field),
                    move.product.default_uom, round=False)
            if qty <= 0.0:
                continue
            if qty > quantity - consumed_qty:
                qty = quantity - consumed_qty
            if consumed_qty >= quantity:
                break

            if type_.endswith('supplier'):
                with Transaction().set_context(date=move.effective_date):
                    unit_price = Currency.compute(move.currency,
                        move.unit_price, move.company.currency, round=False)
                cost_price = Uom.compute_price(move.uom,
                        unit_price, move.product.default_uom)
            else:
                cost_price = move.cost_price

            yield (move, qty, cost_price)
            consumed_qty += qty

    @classmethod
    def update_anglo_saxon_quantity_product_cost(cls, product, moves,
            quantity, uom, type_):
        '''
        Return the cost for quantity based on lines.
        Update anglo_saxon_quantity on the concerned moves.
        '''
        pool = Pool()
        Uom = pool.get('product.uom')

        assert all(m.product == product for m in moves), 'wrong product'
        assert type_.startswith('in_') or type_.startswith('out_'), \
            'wrong type'

        total_qty = Uom.compute_qty(uom, quantity, product.default_uom,
                round=False)

        as_qty_field = _get_field(type_)
        cost = Decimal('0.0')
        consumed_qty = 0.0
        for move, move_qty, move_cost_price in cls._get_anglo_saxon_move(
                moves, total_qty, type_):
            consumed_qty += move_qty

            cost += move_cost_price * Decimal(str(move_qty))

            move_qty = Uom.compute_qty(
                product.default_uom, move_qty, move.uom, round=False)

            # Avoid float rounding issue but allow only rounding precision lost
            new_qty = (getattr(move, as_qty_field) or 0.0) + move_qty
            assert move.uom.round(new_qty) <= move.quantity
            new_qty = min(new_qty, move.quantity)
            cls.write([move], {
                    as_qty_field: new_qty,
                    })

        if consumed_qty < total_qty:
            qty = total_qty - consumed_qty
            consumed_qty += qty
            cost += product.cost_price * Decimal(str(qty))
        return cost

    @classmethod
    def copy(cls, moves, default=None):
        if default is None:
            default = {}
        else:
            default = default.copy()
        for prefix in ('in_', 'out_'):
            default.setdefault(prefix + 'anglo_saxon_quantity',
                getattr(cls, 'default_%sanglo_saxon_quantity' % prefix)())
        return super(Move, cls).copy(moves, default=default)