Commit 79ecff23 authored by Luca Cristaldi's avatar Luca Cristaldi

Merge files into association

And fix  party code
parent 4d721a7d
......@@ -2,8 +2,7 @@
# this repository contains the full copyright notices and license terms.
from trytond.pool import Pool
from . import account
from . import member
from . import membership
from . import association
from . import configuration
from . import ir
......@@ -13,22 +12,22 @@ __all__ = ['register']
def register():
Pool.register(
account.Move,
association.Member,
association.PrintMembersBookStart,
association.MembershipType,
association.Period,
association.Fee,
association.Membership,
association.GenerateFeeStart,
configuration.Configuration,
configuration.MemberSequence,
ir.Cron,
member.Member,
member.PrintMembersBookStart,
membership.MembershipType,
membership.Period,
membership.Fee,
membership.Membership,
membership.GenerateFeeStart,
module='association', type_='model')
Pool.register(
member.MembersBookWizard,
membership.PostFee,
membership.GenerateFee,
association.MembersBookWizard,
association.PostFee,
association.GenerateFee,
module='association', type_='wizard')
Pool.register(
member.MembersBookReport,
association.MembersBookReport,
module='association', type_='report')
......@@ -3,19 +3,25 @@
from decimal import Decimal
from trytond.config import config
from trytond.i18n import gettext
from trytond.model import ModelSQL, ModelView, Unique, fields
from trytond.pool import Pool
from trytond.pyson import And, Eval, If, Bool
from trytond.model import Workflow, ModelView, ModelSQL, fields, Unique
from trytond.model.exceptions import AccessError
from trytond.pool import Pool
from trytond.pyson import Eval, If, Bool, And
from trytond.report import Report
from trytond.tools import lstrip_wildcard
from trytond.transaction import Transaction
from trytond.wizard import StateTransition, Wizard, StateView, Button
from trytond.wizard import (Wizard, StateView, Button, StateReport,
StateTransition)
from .exceptions import (PeriodDateOverlapError, AmountLessThanZeroError,
PartyAccountPayableRequiredError)
PartyAccountPayableRequiredError,
MemberUnpaidFeeError)
__all__ = [
'Membership', 'Period', 'Fee', 'MembershipType', 'PostFee', 'GenerateFee',
'GenerateFeeStart'
'Member', 'MembersBookWizard', 'PrintMembersBookStart',
'MembersBookReport', 'Membership', 'Period', 'Fee', 'MembershipType',
'PostFee', 'GenerateFee', 'GenerateFeeStart'
]
fee_digit = (16, config.getint('membership', 'fee_decimal', default=4))
......@@ -33,6 +39,229 @@ _MOVE_STATES = [
]
class Member(Workflow, ModelSQL, ModelView):
'Member'
__name__ = "association.member"
_states = {'readonly': Eval('state') != 'draft'}
_depends = ['state']
state = fields.Selection(_MEMBER_STATES, "State", readonly=True)
code = fields.Char("Code", select=True,
states={
'readonly': Eval('code_readonly', True),
'required': Eval('state') != 'draft'
},
depends=_depends + ['code_readonly'],
help="The internal identifier for the associate.")
code_readonly = fields.Function(fields.Boolean("Code Readonly"),
'get_code_readonly')
company = fields.Many2One('company.company', "Company",
states={'readonly': Eval('state') != 'draft'},
depends=_depends,
required=True,
help="The association the member belongs to.")
party = fields.Many2One('party.party', "Party",
states={'readonly': Eval('state') != 'draft'},
depends=_depends,
required=True,
help="The party that represents the member.")
join_date = fields.Date("Join Date",
states={
'readonly':
(Eval('state') != 'draft') | Eval('join_date'),
'required':
Eval('state') != 'draft'
},
domain=[
If(
(Eval('join_date')) & (Eval('leave_date')),
('join_date', '<=', Eval('leave_date')),
(),
)
],
depends=_depends + ['leave_date'],
help="The date the member joined the association.")
leave_date = fields.Date("Leave Date",
domain=[
If(
(Eval('join_date')) &
(Eval('leave_date')),
('leave_date', '>=', Eval('join_date')),
(),
)
],
depends=_depends + ['join_date'],
states={
'invisible': Eval('state') == 'draft',
'required': Eval('state') == 'stopped',
'readonly': Eval('state') != 'running'
},
help="The date the member left the association.")
memberships = fields.One2Many('association.membership', 'member',
"Memberships",
domain=[
('company', '=', Eval('company', -1))
],
depends=_depends + ['company'],
states=_states)
del _states, _depends
@classmethod
def __setup__(cls):
super().__setup__()
t = cls.__table__()
cls._sql_constraints = [
('code_uniq', Unique(t, t.code), 'Member code must be unique.'),
]
cls._transitions |= {('draft', 'running'), ('running', 'draft'),
('running', 'stopped')}
cls._buttons.update({
'draft': {
'invisible': Eval('state').in_(['draft', 'stopped']),
'depends': ['state'],
},
'run': {
'invisible': Eval('state').in_(['stopped', 'running']),
'depends': ['state'],
},
'stop': {
'invisible': Eval('state').in_(['draft', 'stopped']),
'depends': ['state'],
},
})
def get_code_readonly(self, name):
return True
@classmethod
def _new_code(cls, **pattern):
pool = Pool()
Sequence = pool.get('ir.sequence')
Configuration = pool.get('association.configuration')
config = Configuration(1)
sequence = config.get_multivalue('member_sequence', **pattern)
if sequence:
return Sequence.get_id(sequence.id)
def get_rec_name(self, name):
return self.party.rec_name
@classmethod
def search_rec_name(cls, name, clause):
if clause[1].startswith('!') or clause[1].startswith('not '):
bool_op = 'AND'
else:
bool_op = 'OR'
code_value = clause[2]
if clause[1].endswith('like'):
code_value = lstrip_wildcard(clause[2])
return [
bool_op,
('code', clause[1], code_value) + tuple(clause[3:]),
('party', ) + tuple(clause[1:]),
]
@classmethod
def copy(cls, members, default=None):
if default is None:
default = {}
else:
default = default.copy()
default.setdefault('code', None)
default.setdefault('leave_date', None)
return super().copy(members, default=default)
@classmethod
def default_state(cls):
return 'draft'
@classmethod
def default_company(cls):
return Transaction().context.get('company')
@classmethod
def default_code_readonly(cls, **pattern):
Configuration = Pool().get('association.configuration')
config = Configuration(1)
return bool(config.get_multivalue('member_sequence', **pattern))
@classmethod
@ModelView.button
@Workflow.transition('draft')
def draft(cls, members):
pass
@classmethod
@ModelView.button
@Workflow.transition('running')
def run(cls, members):
for member in members:
if not member.code:
member.code = cls._new_code()
cls.save(members)
@classmethod
@ModelView.button
@Workflow.transition('stopped')
def stop(cls, members):
pool = Pool()
Fee = pool.get('association.membership.fee')
pending_fees = Fee.search([('member', 'in', members)])
if not all(x.paid for x in pending_fees):
raise MemberUnpaidFeeError(
gettext('association.msg_unpaid_fee',
member=", ".join([x.rec_name for x in members])))
class MembersBookReport(Report):
'Members Book report'
__name__ = 'association.member_print'
@classmethod
def get_context(cls, records, data):
pool = Pool()
Member = pool.get('association.member')
Company = pool.get('company.company')
clause = [('state', '!=', 'draft'), ('company', '=', data['company'])]
context = super().get_context(records, data)
members = Member.search(clause)
context["members"] = members
context["company"] = Company(data['company'])
return context
class PrintMembersBookStart(ModelView):
'Print Members Book'
__name__ = 'association.member.print_member_book.start'
company = fields.Many2One('company.company', 'Company', required=True)
@staticmethod
def default_company():
return Transaction().context.get('company')
class MembersBookWizard(Wizard):
'Print member book'
__name__ = 'association.member.print_member_book'
start = StateView(
'association.member.print_member_book.start',
'association.print_member_book_start_view_from', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Print', 'print_', 'tryton-print', default=True)
])
print_ = StateReport('association.member_print')
def do_print_(self, action):
data = {
'company': self.start.company.id,
}
return action, data
class MembershipType(ModelSQL, ModelView):
"""Membership Type"""
__name__ = 'association.membership.type'
......
This diff is collapsed.
......@@ -15,7 +15,7 @@ class Configuration(
"""Association Configuration"""
__name__ = 'association.configuration'
member_sequence = fields.MultiValue(
fields.Many2One('ir.sequence', "Member Sequence", required=True,
fields.Many2One('ir.sequence', "Member Sequence",
domain=[
('company', 'in',
[Eval('context', {}).get('company', -1), None]),
......@@ -29,12 +29,10 @@ class Configuration(
cls.multivalue_model('member_sequence'),
'default_member_sequence', lambda: None)()
class MemberSequence(ModelSQL, CompanyValueMixin):
"""Member Configuration Sequence"""
__name__ = 'association.configuration.member_sequence'
member_sequence = fields.Many2One('ir.sequence', "Member Sequence",
required=True,
domain=[
('company', 'in',
[Eval('company', -1), None]),
......@@ -49,4 +47,4 @@ class MemberSequence(ModelSQL, CompanyValueMixin):
try:
return ModelData.get_id('association', 'sequence_member')
except KeyError:
return None
return None
\ No newline at end of file
# 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 trytond.model import Workflow, ModelView, ModelSQL, fields, Unique
from trytond.pyson import Eval, If
from trytond.tools import lstrip_wildcard
from trytond.transaction import Transaction
from trytond.pool import Pool
from trytond.i18n import gettext
from trytond.wizard import Wizard, StateView, Button, StateReport
from trytond.report import Report
from .exceptions import MemberUnpaidFeeError
__all__ = [
'Member', 'MembersBookWizard', 'PrintMembersBookStart', 'MembersBookReport'
]
class Member(Workflow, ModelSQL, ModelView):
'Member'
__name__ = "association.member"
_states = {'readonly': Eval('state') != 'draft'}
_depends = ['state']
state = fields.Selection([
('draft', 'Draft'),
('running', 'Running'),
('stopped', 'Stopped'),
],
"State",
readonly=True)
code = fields.Char("Code", select=True,
states={
'readonly': Eval('code_readonly', True),
'required': Eval('state') != 'draft'
},
depends=_depends + ['code_readonly'],
help="The internal identifier for the associate.")
code_readonly = fields.Function(fields.Boolean("Code Readonly"),
'get_code_readonly')
company = fields.Many2One('company.company', "Company",
states={'readonly': Eval('state') != 'draft'},
depends=_depends,
required=True,
help="The association the member belongs to.")
party = fields.Many2One('party.party', "Party",
states={'readonly': Eval('state') != 'draft'},
depends=_depends,
required=True,
help="The party that represents the member.")
join_date = fields.Date("Join Date",
states={
'readonly':
(Eval('state') != 'draft') | Eval('join_date'),
'required':
Eval('state') != 'draft'
},
domain=[
If(
(Eval('join_date')) & (Eval('leave_date')),
('join_date', '<=', Eval('leave_date')),
(),
)
],
depends=_depends + ['leave_date'],
help="The date the member joined the association.")
leave_date = fields.Date("Leave Date",
domain=[
If(
(Eval('join_date')) &
(Eval('leave_date')),
('leave_date', '>=', Eval('join_date')),
(),
)
],
depends=_depends + ['join_date'],
states={
'invisible': Eval('state') == 'draft',
'required': Eval('state') == 'stopped',
'readonly': Eval('state') != 'running'
},
help="The date the member left the association.")
memberships = fields.One2Many('association.membership', 'member',
"Memberships",
domain=[
('company', '=', Eval('company', -1))
],
depends=_depends + ['company'],
states=_states)
del _states, _depends
@classmethod
def __setup__(cls):
super().__setup__()
t = cls.__table__()
cls._sql_constraints = [
('code_uniq', Unique(t, t.code), 'Member code must be unique.'),
]
cls._transitions |= {('draft', 'running'), ('running', 'draft'),
('running', 'stopped')}
cls._buttons.update({
'draft': {
'invisible': Eval('state').in_(['draft', 'stopped']),
'depends': ['state'],
},
'run': {
'invisible': Eval('state').in_(['stopped', 'running']),
'depends': ['state'],
},
'stop': {
'invisible': Eval('state').in_(['draft', 'stopped']),
'depends': ['state'],
},
})
def get_code_readonly(self, name):
return True
@classmethod
def _new_code(cls, **pattern):
pool = Pool()
Sequence = pool.get('ir.sequence')
Configuration = pool.get('association.configuration')
config = Configuration(1)
sequence = config.get_multivalue('member_sequence', **pattern)
if sequence:
return Sequence.get_id(sequence.id)
def get_rec_name(self, name):
return self.party.rec_name
@classmethod
def search_rec_name(cls, name, clause):
if clause[1].startswith('!') or clause[1].startswith('not '):
bool_op = 'AND'
else:
bool_op = 'OR'
code_value = clause[2]
if clause[1].endswith('like'):
code_value = lstrip_wildcard(clause[2])
return [
bool_op,
('code', clause[1], code_value) + tuple(clause[3:]),
('party', ) + tuple(clause[1:]),
]
@classmethod
def copy(cls, members, default=None):
if default is None:
default = {}
else:
default = default.copy()
default.setdefault('code', None)
default.setdefault('leave_date', None)
return super().copy(members, default=default)
@classmethod
def default_state(cls):
return 'draft'
@classmethod
def default_company(cls):
return Transaction().context.get('company')
@classmethod
def default_code_readonly(cls, **pattern):
Configuration = Pool().get('association.configuration')
config = Configuration(1)
return bool(config.get_multivalue('member_sequence', **pattern))
@classmethod
@ModelView.button
@Workflow.transition('draft')
def draft(cls, members):
pass
@classmethod
@ModelView.button
@Workflow.transition('running')
def run(cls, members):
for member in members:
if not member.code:
member.code = cls._new_code()
cls.save(members)
@classmethod
@ModelView.button
@Workflow.transition('stopped')
def stop(cls, members):
pool = Pool()
Fee = pool.get('association.membership.fee')
pending_fees = Fee.search([('member', 'in', members)])
if not all(x.paid for x in pending_fees):
raise MemberUnpaidFeeError(
gettext('association.msg_unpaid_fee',
member=", ".join([x.rec_name for x in members])))
class MembersBookReport(Report):
'Members Book report'
__name__ = 'association.member_print'
@classmethod
def get_context(cls, records, data):
pool = Pool()
Member = pool.get('association.member')
Company = pool.get('company.company')
clause = [('state', '!=', 'draft'), ('company', '=', data['company'])]
context = super().get_context(records, data)
members = Member.search(clause)
context["members"] = members
context["company"] = Company(data['company'])
return context
class PrintMembersBookStart(ModelView):
'Print Members Book'
__name__ = 'association.member.print_member_book.start'
company = fields.Many2One('company.company', 'Company', required=True)
@staticmethod
def default_company():
return Transaction().context.get('company')
class MembersBookWizard(Wizard):
'Print member book'
__name__ = 'association.member.print_member_book'
start = StateView(
'association.member.print_member_book.start',
'association.print_member_book_start_view_from', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Print', 'print_', 'tryton-print', default=True)
])
print_ = StateReport('association.member_print')
def do_print_(self, action):
data = {
'company': self.start.company.id,
}
return action, data
This diff is collapsed.
......@@ -6,7 +6,6 @@ depends:
ir
party
xml:
member.xml
membership.xml
association.xml
message.xml
configuration.xml
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment