Commit 39f69895 authored by Luca Cristaldi's avatar Luca Cristaldi

Fix documentation and style

parent 709f9b81
......@@ -11,11 +11,10 @@ from trytond.report import Report
from trytond.tools import lstrip_wildcard
from trytond.transaction import Transaction
from trytond.wizard import (Wizard, StateView, Button, StateReport,
StateTransition)
StateTransition)
from .exceptions import (PeriodDateOverlapError, AmountLessThanZeroError,
PartyAccountPayableRequiredError,
MemberUnpaidFeeError)
PartyAccountPayableRequiredError, MemberUnpaidFeeError)
__all__ = [
......@@ -374,23 +373,22 @@ class Membership(ModelSQL, ModelView):
transaction.database.lock(connection, self._table)
table = self.__table__()
cursor = connection.cursor()
cursor.execute(
*table.select(table.id,
where=(((table.start_date <= self.start_date)
& (table.end_date >= self.start_date))
| ((table.start_date <= self.end_date)
& (table.end_date >= self.end_date))
| ((table.start_date >= self.start_date)
& (table.end_date <= self.end_date)))
& (table.membership_type == self.membership_type.id)
& (table.id != self.id)))
cursor.execute(*table.select(table.id,
where=(((table.start_date <= self.start_date)
& (table.end_date >= self.start_date))
| ((table.start_date <= self.end_date)
& (table.end_date >= self.end_date))
| ((table.start_date >= self.start_date)
& (table.end_date <= self.end_date)))
& (table.membership_type == self.membership_type.id)
& (table.id != self.id)))
period_id = cursor.fetchone()
if period_id:
overlapping_period = self.__class__(period_id[0])
raise PeriodDateOverlapError(
gettext('association.msg_overlapping_membership',
first=self.rec_name,
second=overlapping_period.rec_name))
first=self.rec_name,
second=overlapping_period.rec_name))
@classmethod
def default_company(cls):
......@@ -470,16 +468,15 @@ class Period(ModelSQL, ModelView):
transaction.database.lock(connection, self._table)
table = self.__table__()
cursor = connection.cursor()
cursor.execute(
*table.select(table.id,
where=(((table.start_date <= self.start_date)
& (table.end_date >= self.start_date))
| ((table.start_date <= self.end_date)
& (table.end_date >= self.end_date))
| ((table.start_date >= self.start_date)
& (table.end_date <= self.end_date)))
& (table.membership_type == self.membership_type.id)
& (table.id != self.id)))
cursor.execute(*table.select(table.id,
where=(((table.start_date <= self.start_date)
& (table.end_date >= self.start_date))
| ((table.start_date <= self.end_date)
& (table.end_date >= self.end_date))
| ((table.start_date >= self.start_date)
& (table.end_date <= self.end_date)))
& (table.membership_type == self.membership_type.id)
& (table.id != self.id)))
period_id = cursor.fetchone()
if period_id:
overlapping_period = self.__class__(period_id[0])
......@@ -644,12 +641,12 @@ class Fee(ModelSQL, ModelView):
]
return Move(period=period_id,
journal=self.period.membership_type.journal,
date=move_date,
origin=self,
company=self.company,
description=self.period.name,
lines=move_lines)
journal=self.period.membership_type.journal,
date=move_date,
origin=self,
company=self.company,
description=self.period.name,
lines=move_lines)
@classmethod
@ModelView.button
......@@ -689,8 +686,7 @@ class Fee(ModelSQL, ModelView):
return period
active_lines = MembershipLine.search([('member.join_date', '<=', date),
('member.state', '=', 'running')
])
('member.state', '=', 'running')])
fees = []
for line in active_lines:
......@@ -699,8 +695,8 @@ class Fee(ModelSQL, ModelView):
for period in period_valid(line, date):
if period not in created_period:
fee = Fee(member=line.member,
period=period,
company=line.member.company)
period=period,
company=line.member.company)
fees.append(fee)
cls.save(fees)
......
......@@ -5,7 +5,7 @@ from trytond.pyson import Eval
from trytond.pool import Pool
from trytond.modules.company.model import (CompanyMultiValueMixin,
CompanyValueMixin)
CompanyValueMixin)
__all__ = ['Configuration', 'MemberSequence']
......
......@@ -40,40 +40,39 @@ preferences.
A Membership type is defined by:
- Name: The name of the Membership
- Journal: The Journal that will be used for posting accounting move
- Name: The name of the Membership.
- Journal: The Journal that will be used for posting accounting move.
- Account Revenue: The account revenue that will be used
for posting accounting move
- Periods: A list of Periods
for posting accounting move.
- Periods: A list of Periods.
Print Member's Book
*******************
This wizard will print a Report of all the member
that are not in the draft state.
The Member's Book prints a report for all members.
Period
------
Membership period
-----------------
A periods define a date range and what the member should pay for the period
A period is a range of dates where a fee amount is settled.
A period is defined by:
- Start Date: The starting date of the period
- End Date: The ending date of the period
- Fee: The amount that the member should pay for this period
- Start Date: The starting date of the period.
- End Date: The ending date of the period.
- Amount: The fee amount for this period.
Fee
---
A fee is defined as:
A fee is the payment of a member for a specific membership period.
- Member: The Member associated with this fee
- Period: The Period associated with this fee
- Move: The move associated with this fee
A fee is defined as:
The fee will be considered as paid when the move is reconciled and posted.
You can post the move via the Post button/action, or manually.
- Member: The member associated with this fee.
- Period: The period associated with this fee.
- Move: The move associated with this fee.
- Paid: The payment state of the fee.
Create Fees Wizard
******************
......
===============
Member Scenario
===============
========================
Honorary member scenario
========================
Imports::
......@@ -14,7 +14,7 @@ Imports::
... get_company
>>> from trytond.modules.account.tests.tools import create_fiscalyear, \
... create_chart, get_accounts, create_tax, create_tax_code
>>> from trytond.modules.association.tests.tools import create_period
>>> from trytond.modules.association.tests.tools import create_membership_type
>>> from decimal import *
>>> today = datetime.date.today()
......@@ -59,26 +59,13 @@ Create member::
>>> member.party = party
>>> member.save()
Get a revenue journal::
>>> Journal = Model.get('account.journal')
>>> journal_revenue, = Journal.find([
... ('code', '=', 'REV'),
... ])
Create honorary membership::
>>> Membership = Model.get('association.membership.type')
>>> Period = Model.get('association.membership.period')
>>> honorary = Membership()
>>> honorary.name = "testo"
>>> honorary.account_revenue = revenue
>>> honorary.journal = journal_revenue
>>> start_date = datetime.date(2018,1,1)
>>> 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)]
>>> _ = [ honorary.periods.new(start_date=period[0],end_date=period[1], name=period[2], amount=Decimal('0.0')) for period in datedeltas ]
>>> honorary = create_membership_type(
... name="honorary",
... amount=Decimal(0.0),
... company=company)
>>> honorary.save()
......@@ -89,14 +76,14 @@ Add membership to member::
Enroll member::
>>> member.join_date = start_date
>>> member.join_date = today
>>> member.click("run")
>>> member.save()
Create fee lines::
>>> create_fee = Wizard('association.membership.fee_create')
>>> create_fee.form.date = start_date + datetime.timedelta(weeks=40)
>>> create_fee.form.date = today + datetime.timedelta(weeks=40)
>>> create_fee.execute('create_')
Check fees::
......
......@@ -4,19 +4,21 @@ Member Scenario
Imports::
>>> import datetime
>>> from dateutil.relativedelta import relativedelta
>>> from decimal import Decimal
>>> from operator import attrgetter
>>> from proteus import Model, Wizard
>>> from trytond.tests.tools import activate_modules
>>> from trytond.modules.company.tests.tools import create_company, \
... get_company
>>> from trytond.modules.account.tests.tools import create_fiscalyear, \
... create_chart, get_accounts, create_tax, create_tax_code
>>> from trytond.modules.association.tests.tools import create_period
>>> from decimal import *
>>> today = datetime.date.today()
>>> import datetime
>>> from dateutil.relativedelta import relativedelta
>>> from decimal import Decimal
>>> from operator import attrgetter
>>> from proteus import Model, Wizard
>>> from trytond.tests.tools import activate_modules
>>> from trytond.modules.company.tests.tools import create_company, \
... get_company
>>> from trytond.modules.account.tests.tools import create_fiscalyear, \
... create_chart, get_accounts
>>> from trytond.modules.association.tests.tools import \
... create_membership_type
>>> from decimal import *
>>> today = datetime.date.today()
>>> timedelta = relativedelta(months=1)
Install association::
......@@ -50,51 +52,25 @@ Create party::
>>> 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([
... ('code', '=', 'REV'),
... ])
>>> Membership = Model.get('association.membership.type')
>>> membership = Membership()
>>> membership.name = "testo"
>>> membership.journal = journal_revenue
>>> membership.account_revenue = revenue
>>> start_date = datetime.date.today()
>>> timedelta = datetime.timedelta(weeks=4)
>>> fiscalMonth = 13
>>> 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 membership type::
>>> membership_type = create_membership_type(name="test", company=company)
>>> membership_type.save()
Create member::
>>> Member = Model.get('association.member')
>>> member = Member()
>>> member.party = party
>>> membership_line = member.memberships.new(membership_type=membership)
>>> membership_line = member.memberships.new(membership_type=membership_type)
>>> member.save()
Test membership inverse date::
>>> membership_line = member.memberships.new(
... membership_type=membership,
... start_date=start_date +timedelta,
... end_date=start_date)
... membership_type=membership_type,
... start_date=today + timedelta,
... end_date=today)
>>> member.save() #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
......@@ -102,11 +78,6 @@ Test membership inverse date::
>>> member.memberships.remove(membership_line)
>>> member.save()
Test membership unique::
>>> membership_line = member.memberships.new(membership_type=membership)
>>> member.save()
Test memebrship fee::
>>> Period = Model.get('association.membership.period')
......@@ -120,7 +91,7 @@ Test memebrship fee::
Make member active::
>>> member.join_date = start_date
>>> member.join_date = today
>>> member.click('run')
>>> member.state
'running'
......@@ -138,7 +109,7 @@ Test memebrship fee move::
Test member leave_date < join_date::
>>> member.leave_date = start_date - timedelta
>>> member.leave_date = today - timedelta
>>> member.save() #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
......@@ -146,7 +117,7 @@ Test member leave_date < join_date::
Test member expulsion::
>>> member.leave_date = start_date + timedelta
>>> member.leave_date = today + timedelta
>>> member.click('stop') #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
......
......@@ -14,7 +14,7 @@ Imports::
... get_company
>>> from trytond.modules.account.tests.tools import create_fiscalyear, \
... create_chart, get_accounts, create_tax, create_tax_code
>>> from trytond.modules.association.tests.tools import create_period
>>> from trytond.modules.association.tests.tools import create_membership_type
>>> from decimal import *
>>> today = datetime.date.today()
......@@ -59,53 +59,20 @@ Create member::
>>> member.party = party
>>> member.save()
Get a revenue journal::
>>> Journal = Model.get('account.journal')
>>> journal_revenue, = Journal.find([
... ('code', '=', 'REV'),
... ])
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)
>>> start_date = datetime.date(2018,1,1)
>>> fiscalMonth = 13
>>> timedelta = datetime.timedelta(weeks=4)
>>> Membership = Model.get('association.membership.type')
>>> Period = Model.get('association.membership.period')
>>> membership1 = Membership()
>>> membership1.name = "membership1"
>>> membership1.account_revenue = revenue
>>> membership1.journal = journal_revenue
>>> periods1 = []
>>> for period in periodgen(start_date,timedelta,fiscalMonth):
... newPeriod = membership1.periods.new(
... start_date=period[0],
... end_date=period[1],
... name="test",
... amount=Decimal(42))
... periods1.append(newPeriod)
>>> membership1.save()
Create membership type::
>>> membership_type = create_membership_type(name="test", company=company)
>>> membership_type.save()
Add membership to member::
>>> _ = member.memberships.new(
... membership_type=membership1,
... )
>>> _ = member.memberships.new(membership_type=membership_type)
>>> member.save()
Enroll member::
>>> member.join_date = start_date + datetime.timedelta(weeks=10)
>>> member.join_date = today + relativedelta(day=1,month=1)
>>> member.save()
>>> member.click("run")
......@@ -113,7 +80,7 @@ Create fee lines::
>>> Fee = Model.get('association.membership.fee')
>>> create_fee = Wizard('association.membership.fee_create')
>>> create_fee.form.date = start_date + datetime.timedelta(weeks=40)
>>> create_fee.form.date = today + relativedelta(months=3)
>>> create_fee.execute('create_')
>>> len(Fee.find([])) > 0
True
......@@ -122,14 +89,14 @@ Create fee after change date::
>>> before_fees = set(Fee.find([]))
>>> member.click("draft")
>>> new_date = start_date - datetime.timedelta(weeks=10)
>>> new_date = today + relativedelta(months=4)
>>> member.join_date = new_date
>>> member.save()
>>> member.click("run")
>>> create_fee = Wizard('association.membership.fee_create')
>>> create_fee.form.date = start_date + datetime.timedelta(weeks=40)
>>> create_fee.form.date = today + relativedelta(month=6)
>>> create_fee.execute('create_')
>>> after_fees = set(Fee.find([]))
>>> newfees = after_fees - before_fees
>>> all(map(lambda x: x.period.start_date >= new_date, newfees))
>>> all(map(lambda x: x.period.today >= new_date, newfees))
True
===============
Member Scenario
===============
===================
Membership Scenario
===================
Imports::
......@@ -14,7 +14,7 @@ Imports::
... get_company
>>> from trytond.modules.account.tests.tools import create_fiscalyear, \
... create_chart, get_accounts, create_tax, create_tax_code
>>> from trytond.modules.association.tests.tools import create_period
>>> from trytond.modules.association.tests.tools import create_membership_type
>>> from decimal import *
>>> today = datetime.date.today()
......@@ -57,37 +57,47 @@ Create member::
>>> member.party = party
>>> member.save()
Get a revenue journal::
>>> Journal = Model.get('account.journal')
>>> journal_revenue, = Journal.find([
... ('code', '=', 'REV'),
... ])
Create membership::
>>> Membership = Model.get('association.membership.type')
>>> Period = Model.get('association.membership.period')
>>> membership = Membership()
>>> membership.name = "testo"
>>> membership.account_revenue = revenue
>>> membership.journal = journal_revenue
>>> start_date = datetime.date(2018,1,1)
>>> 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 ]
>>> membership.save()
>>> overlapping =membership.periods.new(start_date=start_date,end_date=start_date+timedelta,name="overlapping",amount=Decimal(42)).save() #doctest: +IGNORE_EXCEPTION_DETAIL
Create membership type::
>>> membership_type = create_membership_type(name="test", company=company)
>>> membership_type.save()
Check overlapping date::
>>> delta = relativedelta(weeks=4)
>>> overlapping = membership_type.periods.new(
... start_date=today,
... end_date=today+delta,
... name="overlapping",
... amount=Decimal(42))
>>> overlapping.save() #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
PeriodDateOverlapError: ...
>>> new_date = datetime.date(2020,1,1)
>>> inverted = membership.periods.new(start_date=new_date + timedelta,end_date=start_date,name="inverted",amount=Decimal(42)).save() #doctest: +IGNORE_EXCEPTION_DETAIL
Check inverted date::
>>> new_date = today + relativedelta(years=2)
>>> inverted = membership_type.periods.new(
... start_date=new_date + delta,
... end_date=new_date,
... name="inverted",
... amount=Decimal(42))
>>> inverted.save() #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
DomainValidationError: ...
>>> negative = membership.periods.new(start_date=new_date,end_date=new_date + timedelta,name="negative 1",amount=Decimal(-10)).save() #doctest: +IGNORE_EXCEPTION_DETAIL
Check negative amount::
>>> neg_type = create_membership_type(name="test", company=company)
>>> negative = neg_type.periods.new(
... start_date=new_date,
... end_date=new_date + delta,
... name="negative",
... amount=Decimal(-10))
>>> neg_type.save() #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
AmountLessThanZeroError: ...
......
===============
Member Scenario
===============
==============
Membership Fee
==============
Imports::
......@@ -14,7 +14,7 @@ Imports::
... get_company
>>> from trytond.modules.account.tests.tools import create_fiscalyear, \
... create_chart, get_accounts, create_tax, create_tax_code
>>> from trytond.modules.association.tests.tools import create_period
>>> from trytond.modules.association.tests.tools import create_membership_type
>>> from decimal import *
>>> today = datetime.date.today()
......@@ -66,68 +66,32 @@ Get a revenue journal::
... ('code', '=', 'REV'),
... ])
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)
>>> start_date = datetime.date(2018,1,1)
>>> fiscalMonth = 13
>>> timedelta = datetime.timedelta(weeks=4)
>>> Membership = Model.get('association.membership.type')
>>> Period = Model.get('association.membership.period')
>>> membership1 = Membership()
>>> membership1.name = "membership1"
>>> membership1.account_revenue = revenue
>>> membership1.journal = journal_revenue
>>> periods1 = []
>>> for period in periodgen(start_date,timedelta,fiscalMonth):
... newPeriod = membership1.periods.new(
... start_date=period[0],
... end_date=period[1],
... name="test",
... amount=Decimal(42))
... periods1.append(newPeriod)
>>> membership1.save()
>>> start_date = datetime.date(2018,1,1)
>>> membership2 = Membership()
>>> membership2.name = "membership2:Electric boogaloo"
>>> membership2.account_revenue = revenue
>>> membership2.journal = journal_revenue
>>> periods2 = []
>>> for period in periodgen(start_date,timedelta,fiscalMonth):
... newPeriod = membership2.periods.new(
... start_date=period[0],
... end_date=period[1],
... name="test",
... amount=Decimal(42))
... periods2.append(newPeriod)
>>> membership2.save()
Create membership types::
>>> membership_type1 = create_membership_type(name="test1", company=company)
>>> membership_type1.save()
>>> membership_type2 = create_membership_type(name="test2", company=company)
>>> membership_type2.save()
Add membership to member::
>>> _ = member.memberships.new(
... membership_type=membership1,
... start_date = start_date + datetime.timedelta(weeks=4),
... end_date = start_date + datetime.timedelta(weeks=50),
... membership_type=membership_type1,
... start_date = today + datetime.timedelta(weeks=4),
... end_date = today + datetime.timedelta(weeks=50),
... )
>>> _ = member.memberships.new(
... membership_type=membership2,
... start_date = start_date + datetime.timedelta(weeks=4),
... end_date = start_date + datetime.timedelta(weeks=50),
... membership_type=membership_type2,
... start_date = today + datetime.timedelta(weeks=4),
... end_date = today + datetime.timedelta(weeks=50),
... )
>>> member.join_date = start_date + datetime.timedelta(weeks=6)
>>> member.leave_date = start_date + datetime.timedelta(weeks=35)
>>> member.join_date = today + datetime.timedelta(weeks=6)
>>> member.leave_date = today + datetime.timedelta(weeks=35)
>>> member.save()
Enroll member::
>>> member.join_date = start_date
>>> member.join_date = today
>>> member.click("run")
>>> member.save()
......@@ -135,7 +99,7 @@ Create fee lines::
>>> Fee = Model.get('association.membership.fee')
>>> create_fee = Wizard('association.membership.fee_create')
>>> create_fee.form.date = start_date + datetime.timedelta(weeks=40)
>>> create_fee.form.date = today + datetime.timedelta(weeks=40)
>>> create_fee.execute('create_')
>>> len(Fee.find([])) > 0
True
......
......@@ -18,34 +18,34 @@ def suite():
suite = test_suite()
suite.addTests(
unittest.TestLoader().loadTestsFromTestCase(AssociationTestCase))
suite.addTests(
doctest.DocFileSuite('scenario_membership.rst',
tearDown=doctest_teardown,
encoding='utf-8',
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE,
checker=doctest_checker))
suite.addTests(
doctest.DocFileSuite('scenario_member.rst',
tearDown=doctest_teardown,
encoding='utf-8',
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE,
checker=doctest_checker))
suite.addTests(
doctest.DocFileSuite('scenario_membership_fee.rst',
tearDown=doctest_teardown,
encoding='utf-8',
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE,
checker=doctest_checker))
suite.addTests(
doctest.DocFileSuite('scenario_honorary_membership.rst',
tearDown=doctest_teardown,
encoding='utf-8',
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE,
checker=doctest_checker))
suite.addTests(
doctest.DocFileSuite('scenario_member_change_date.rst',
tearDown=doctest_teardown,
encoding='utf-8',
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE,
checker=doctest_checker))
suite.addTests(doctest.DocFileSuite(
'scenario_membership.rst',
tearDown=doctest_teardown,
encoding='utf-8',
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE,
checker=doctest_checker))
suite.addTests(doctest.DocFileSuite(
'scenario_member.rst',
tearDown=doctest_teardown,
encoding='utf-8',
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE,
checker=doctest_checker))
suite.addTests(doctest.DocFileSuite(
'scenario_membership_fee.rst',
tearDown=doctest_teardown,
encoding='utf-8',
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE,
checker=doctest_checker))
suite.addTests(doctest.DocFileSuite(
'scenario_honorary_membership.rst',
tearDown=doctest_teardown,
encoding='utf-8',
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE,
checker=doctest_checker))
suite.addTests(doctest.DocFileSuite(
'scenario_member_change_date.rst',
tearDown=doctest_teardown,
encoding='utf-8',
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE,
checker=doctest_checker))
return suite
......@@ -2,17 +2,53 @@
# this repository contains the full copyright notices and license terms.
from proteus import Model