Loading configuration.py +16 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,8 @@ # this repository contains the full copyright notices and license terms. from trytond.model import ModelView, ModelSQL, ModelSingleton, fields from trytond.pyson import Eval from trytond.pool import Pool from trytond.modules.company.model import (CompanyMultiValueMixin, CompanyValueMixin) Loading @@ -21,6 +23,11 @@ class Configuration( ], help="Used to generate the number given to association members.")) @classmethod def default_member_sequence(cls, **pattern): return getattr( cls.multivalue_model('member_sequence'), 'default_member_sequence', lambda: None)() class MemberSequence(ModelSQL, CompanyValueMixin): """Member Configuration Sequence""" Loading @@ -33,3 +40,12 @@ class MemberSequence(ModelSQL, CompanyValueMixin): ('code', '=', 'association.member'), ], depends=['company']) @classmethod def default_member_sequence(cls): pool = Pool() ModelData = pool.get('ir.model.data') try: return ModelData.get_id('association', 'sequence_member') except KeyError: return None No newline at end of file configuration.xml +0 −5 Original line number Diff line number Diff line Loading @@ -23,9 +23,4 @@ this repository contains the full copyright notices and license terms. --> <field name="group" ref="group_association_admin"/> </record> </data> <data noupdate="1"> <record model="association.configuration.member_sequence" id="configuration_member_sequence"> <field name="member_sequence" ref="sequence_member"/> </record> </data> </tryton> membership.py +17 −7 Original line number Diff line number Diff line Loading @@ -124,6 +124,10 @@ class Membership(ModelSQL, ModelView): del _states, _depends @classmethod def default_member_state(cls): return 'draft' @classmethod def validate(cls, memberships): super().validate(memberships) Loading Loading @@ -162,6 +166,8 @@ class Membership(ModelSQL, ModelView): def on_change_with_member_state(self, name=None): if self.member: return self.member.state else: return 'draft' @fields.depends('member', '_parent_member.join_date') def on_change_with_member_join_date(self, name=None): Loading Loading @@ -284,15 +290,10 @@ class Fee(ModelSQL, ModelView): paid = fields.Function(fields.Boolean('paid'), 'is_paid') reconciled = fields.Function(fields.Date("Reconciled"), 'get_reconciled') amount = fields.Function(fields.Numeric("Amount", fee_digit), 'on_change_with_amount') 'on_change_with_amount', searcher='search_amount') del _states @fields.depends('period', '_parent_period.amount') def on_change_with_amount(self, name=None): if self.period: return self.period.amount @classmethod def __setup__(cls): super().__setup__() Loading @@ -300,7 +301,7 @@ class Fee(ModelSQL, ModelView): cls._sql_constraints = [ ('code_uniq', Unique(table, table.member, table.period), gettext('association.msg_period_unique')) "The periods for each member must be unique.") ] cls._buttons.update({ Loading @@ -312,6 +313,11 @@ class Fee(ModelSQL, ModelView): }, }) @fields.depends('period', '_parent_period.amount') def on_change_with_amount(self, name=None): if self.period: return self.period.amount @fields.depends('move', '_parent_move.state') def on_change_with_move_state(self, name=None): if self.move: Loading @@ -329,6 +335,10 @@ class Fee(ModelSQL, ModelView): def default_company(cls): return Transaction().context.get('company') @classmethod def search_amount(cls, name, clause): return [('period.amount',) + tuple(clause[1:])] def get_reconciled(self, name): def get_reconciliation(line): if line.reconciliation and line.reconciliation.delegate_to: Loading message.xml +0 −3 Original line number Diff line number Diff line Loading @@ -21,9 +21,6 @@ this repository contains the full copyright notices and license terms. --> <record model="ir.message" id="msg_party_receivable_missing"> <field name="text">The party "%(party)s" doesn't have an account receivable defined.</field> </record> <record model="ir.message" id="msg_period_unique"> <field name="text">The periods for each member must be unique.</field> </record> <record model="ir.message" id="msg_overlapping_membership"> <field name="text">The membership "%(first)s" overlaps with the period "%(second)s".</field> </record> Loading tests/scenario_member.rst +17 −7 Original line number Diff line number Diff line Loading @@ -41,19 +41,23 @@ Create chart of accounts:: >>> receivable = accounts['receivable'] >>> payable = accounts['payable'] >>> revenue = accounts['revenue'] >>> expense = accounts['expense'] >>> account_tax = accounts['tax'] >>> account_cash = accounts['cash'] Create party:: >>> Party = Model.get('party.party') >>> party = Party(name='Party') >>> party.account_payable = payable >>> party.account_receivable = receivable >>> party.save() Create memberships:: >>> def periodgen(startDate,deltaTime,quantity): ... firstDate = startDate ... for period in range(quantity): ... lastDate = firstDate + deltaTime ... yield (firstDate,lastDate) ... firstDate = lastDate + datetime.timedelta(days=1) >>> Journal = Model.get('account.journal') >>> Move = Model.get('account.move') >>> journal_revenue, = Journal.find([ Loading @@ -68,8 +72,14 @@ Create memberships:: >>> start_date = datetime.date.today() >>> timedelta = datetime.timedelta(weeks=4) >>> fiscalMonth = 13 >>> datedeltas = [(start_date + timedelta*(n-1) + datetime.timedelta(days=1),start_date + timedelta*n,f"period {n}") for n in range(1,fiscalMonth+1)] >>> periods = [ membership.periods.new(start_date=period[0],end_date=period[1], name=period[2], amount=Decimal(42)) for period in datedeltas ] >>> periods = [] >>> for period in periodgen(start_date,timedelta,fiscalMonth): ... newPeriod = membership.periods.new( ... start_date=period[0], ... end_date=period[1], ... name="test", ... amount=Decimal(42)) ... periods.append(newPeriod) >>> membership.save() Create member:: Loading Loading @@ -102,7 +112,7 @@ Test memebrship fee:: >>> Period = Model.get('association.membership.period') >>> Fee = Model.get('association.membership.fee') >>> period, = Period.find(["name","=","period 1"]) >>> period = Period.find([])[0] >>> fee = Fee(member=member,period=period) >>> fee.save() #doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): Loading @@ -120,7 +130,7 @@ Test memebrship fee move:: >>> Period = Model.get('association.membership.period') >>> Fee = Model.get('association.membership.fee') >>> period, = Period.find(["name","=","period 1"]) >>> period = Period.find([])[0] >>> fee = Fee(member=member,period=period) >>> fee.save() >>> fee.click('post_move') Loading Loading
configuration.py +16 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,8 @@ # this repository contains the full copyright notices and license terms. from trytond.model import ModelView, ModelSQL, ModelSingleton, fields from trytond.pyson import Eval from trytond.pool import Pool from trytond.modules.company.model import (CompanyMultiValueMixin, CompanyValueMixin) Loading @@ -21,6 +23,11 @@ class Configuration( ], help="Used to generate the number given to association members.")) @classmethod def default_member_sequence(cls, **pattern): return getattr( cls.multivalue_model('member_sequence'), 'default_member_sequence', lambda: None)() class MemberSequence(ModelSQL, CompanyValueMixin): """Member Configuration Sequence""" Loading @@ -33,3 +40,12 @@ class MemberSequence(ModelSQL, CompanyValueMixin): ('code', '=', 'association.member'), ], depends=['company']) @classmethod def default_member_sequence(cls): pool = Pool() ModelData = pool.get('ir.model.data') try: return ModelData.get_id('association', 'sequence_member') except KeyError: return None No newline at end of file
configuration.xml +0 −5 Original line number Diff line number Diff line Loading @@ -23,9 +23,4 @@ this repository contains the full copyright notices and license terms. --> <field name="group" ref="group_association_admin"/> </record> </data> <data noupdate="1"> <record model="association.configuration.member_sequence" id="configuration_member_sequence"> <field name="member_sequence" ref="sequence_member"/> </record> </data> </tryton>
membership.py +17 −7 Original line number Diff line number Diff line Loading @@ -124,6 +124,10 @@ class Membership(ModelSQL, ModelView): del _states, _depends @classmethod def default_member_state(cls): return 'draft' @classmethod def validate(cls, memberships): super().validate(memberships) Loading Loading @@ -162,6 +166,8 @@ class Membership(ModelSQL, ModelView): def on_change_with_member_state(self, name=None): if self.member: return self.member.state else: return 'draft' @fields.depends('member', '_parent_member.join_date') def on_change_with_member_join_date(self, name=None): Loading Loading @@ -284,15 +290,10 @@ class Fee(ModelSQL, ModelView): paid = fields.Function(fields.Boolean('paid'), 'is_paid') reconciled = fields.Function(fields.Date("Reconciled"), 'get_reconciled') amount = fields.Function(fields.Numeric("Amount", fee_digit), 'on_change_with_amount') 'on_change_with_amount', searcher='search_amount') del _states @fields.depends('period', '_parent_period.amount') def on_change_with_amount(self, name=None): if self.period: return self.period.amount @classmethod def __setup__(cls): super().__setup__() Loading @@ -300,7 +301,7 @@ class Fee(ModelSQL, ModelView): cls._sql_constraints = [ ('code_uniq', Unique(table, table.member, table.period), gettext('association.msg_period_unique')) "The periods for each member must be unique.") ] cls._buttons.update({ Loading @@ -312,6 +313,11 @@ class Fee(ModelSQL, ModelView): }, }) @fields.depends('period', '_parent_period.amount') def on_change_with_amount(self, name=None): if self.period: return self.period.amount @fields.depends('move', '_parent_move.state') def on_change_with_move_state(self, name=None): if self.move: Loading @@ -329,6 +335,10 @@ class Fee(ModelSQL, ModelView): def default_company(cls): return Transaction().context.get('company') @classmethod def search_amount(cls, name, clause): return [('period.amount',) + tuple(clause[1:])] def get_reconciled(self, name): def get_reconciliation(line): if line.reconciliation and line.reconciliation.delegate_to: Loading
message.xml +0 −3 Original line number Diff line number Diff line Loading @@ -21,9 +21,6 @@ this repository contains the full copyright notices and license terms. --> <record model="ir.message" id="msg_party_receivable_missing"> <field name="text">The party "%(party)s" doesn't have an account receivable defined.</field> </record> <record model="ir.message" id="msg_period_unique"> <field name="text">The periods for each member must be unique.</field> </record> <record model="ir.message" id="msg_overlapping_membership"> <field name="text">The membership "%(first)s" overlaps with the period "%(second)s".</field> </record> Loading
tests/scenario_member.rst +17 −7 Original line number Diff line number Diff line Loading @@ -41,19 +41,23 @@ Create chart of accounts:: >>> receivable = accounts['receivable'] >>> payable = accounts['payable'] >>> revenue = accounts['revenue'] >>> expense = accounts['expense'] >>> account_tax = accounts['tax'] >>> account_cash = accounts['cash'] Create party:: >>> Party = Model.get('party.party') >>> party = Party(name='Party') >>> party.account_payable = payable >>> party.account_receivable = receivable >>> party.save() Create memberships:: >>> def periodgen(startDate,deltaTime,quantity): ... firstDate = startDate ... for period in range(quantity): ... lastDate = firstDate + deltaTime ... yield (firstDate,lastDate) ... firstDate = lastDate + datetime.timedelta(days=1) >>> Journal = Model.get('account.journal') >>> Move = Model.get('account.move') >>> journal_revenue, = Journal.find([ Loading @@ -68,8 +72,14 @@ Create memberships:: >>> start_date = datetime.date.today() >>> timedelta = datetime.timedelta(weeks=4) >>> fiscalMonth = 13 >>> datedeltas = [(start_date + timedelta*(n-1) + datetime.timedelta(days=1),start_date + timedelta*n,f"period {n}") for n in range(1,fiscalMonth+1)] >>> periods = [ membership.periods.new(start_date=period[0],end_date=period[1], name=period[2], amount=Decimal(42)) for period in datedeltas ] >>> periods = [] >>> for period in periodgen(start_date,timedelta,fiscalMonth): ... newPeriod = membership.periods.new( ... start_date=period[0], ... end_date=period[1], ... name="test", ... amount=Decimal(42)) ... periods.append(newPeriod) >>> membership.save() Create member:: Loading Loading @@ -102,7 +112,7 @@ Test memebrship fee:: >>> Period = Model.get('association.membership.period') >>> Fee = Model.get('association.membership.fee') >>> period, = Period.find(["name","=","period 1"]) >>> period = Period.find([])[0] >>> fee = Fee(member=member,period=period) >>> fee.save() #doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): Loading @@ -120,7 +130,7 @@ Test memebrship fee move:: >>> Period = Model.get('association.membership.period') >>> Fee = Model.get('association.membership.fee') >>> period, = Period.find(["name","=","period 1"]) >>> period = Period.find([])[0] >>> fee = Fee(member=member,period=period) >>> fee.save() >>> fee.click('post_move') Loading