The fiscal years are created centered on the passed date such that if the current day change during the execution, the fiscal year is still usable. Also fiscal year can be created for a range of dates such that it is guarantee that the dates are in the fiscal year. And finally remove datetime and dateutil import when they are not used. Closes #9977
366 lines
11 KiB
ReStructuredText
366 lines
11 KiB
ReStructuredText
=============================
|
|
Purchase Requisition Scenario
|
|
=============================
|
|
|
|
Imports::
|
|
|
|
>>> import datetime as dt
|
|
>>> from decimal import Decimal
|
|
>>> from proteus import Model, Wizard
|
|
>>> from trytond.tests.tools import activate_modules, set_user
|
|
>>> from trytond.modules.company.tests.tools import (create_company,
|
|
... get_company)
|
|
>>> from trytond.modules.account.tests.tools import (create_chart,
|
|
... get_accounts)
|
|
|
|
>>> today = dt.date.today()
|
|
|
|
Activate purchase_requisition Module::
|
|
|
|
>>> config = activate_modules(['purchase_requisition'])
|
|
|
|
Create company::
|
|
|
|
>>> _ = create_company()
|
|
>>> company = get_company()
|
|
|
|
Create chart of accounts::
|
|
|
|
>>> _ = create_chart(company)
|
|
>>> accounts = get_accounts(company)
|
|
>>> expense = accounts['expense']
|
|
|
|
Create purchase requisition user::
|
|
|
|
>>> User = Model.get('res.user')
|
|
>>> Group = Model.get('res.group')
|
|
>>> Party = Model.get('party.party')
|
|
>>> Employee = Model.get('company.employee')
|
|
>>> requisition_user = User()
|
|
>>> requisition_user.name = 'Requisition'
|
|
>>> requisition_user.login = 'requisition'
|
|
>>> requisition_group, = Group.find([
|
|
... ('name', '=', 'Purchase Requisition')])
|
|
>>> requisition_user.groups.append(requisition_group)
|
|
>>> employee_party = Party(name='Employee')
|
|
>>> employee_party.save()
|
|
>>> employee = Employee(party=employee_party)
|
|
>>> employee.save()
|
|
>>> requisition_user.employees.append(employee)
|
|
>>> requisition_user.employee = employee
|
|
>>> requisition_user.save()
|
|
|
|
>>> party_approval, = Party.duplicate([employee_party], {
|
|
... 'name': 'Employee Approval',
|
|
... })
|
|
>>> employee_approval, = Employee.duplicate([employee], {
|
|
... 'party': party_approval.id,
|
|
... })
|
|
>>> requisition_approval_user, = User.duplicate([requisition_user], {
|
|
... 'name': 'Requisition Approval',
|
|
... 'login': 'requisition_approval',
|
|
... })
|
|
>>> requisition_approval_group, = Group.find([
|
|
... ('name', '=', 'Purchase Requisition Approval')])
|
|
>>> requisition_approval_user.groups.append(requisition_approval_group)
|
|
>>> _ = requisition_approval_user.employees.pop()
|
|
>>> requisition_approval_user.employees.append(employee_approval)
|
|
>>> requisition_approval_user.employee = employee_approval
|
|
>>> requisition_approval_user.save()
|
|
|
|
Create purchase user::
|
|
|
|
>>> purchase_user = User()
|
|
>>> purchase_user.name = 'Purchase'
|
|
>>> purchase_user.login = 'purchase'
|
|
>>> purchase_group, = Group.find([('name', '=', 'Purchase')])
|
|
>>> purchase_user.groups.append(purchase_group)
|
|
>>> purchase_request_group, = Group.find(
|
|
... [('name', '=', 'Purchase Request')])
|
|
>>> purchase_user.groups.append(purchase_request_group)
|
|
>>> purchase_user.save()
|
|
|
|
|
|
Create supplier::
|
|
|
|
>>> supplier = Party(name='Supplier')
|
|
>>> supplier.save()
|
|
>>> supplier2 = Party(name='Supplier2')
|
|
>>> supplier2.save()
|
|
|
|
Set default account::
|
|
|
|
>>> Configuration = Model.get('account.configuration')
|
|
>>> config = Configuration(1)
|
|
>>> config.default_category_account_expense = expense
|
|
>>> config.save()
|
|
|
|
Create account category::
|
|
|
|
>>> ProductCategory = Model.get('product.category')
|
|
>>> account_category = ProductCategory(name="Account Category")
|
|
>>> account_category.accounting = True
|
|
>>> account_category.account_expense = expense
|
|
>>> account_category.save()
|
|
|
|
Create product::
|
|
|
|
>>> ProductUom = Model.get('product.uom')
|
|
>>> ProductTemplate = Model.get('product.template')
|
|
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
|
|
|
>>> template = ProductTemplate()
|
|
>>> template.name = 'Product'
|
|
>>> template.default_uom = unit
|
|
>>> template.type = 'goods'
|
|
>>> template.list_price = Decimal('20')
|
|
>>> template.purchasable = True
|
|
>>> template.account_category = account_category
|
|
>>> product, = template.products
|
|
>>> product.cost_price = Decimal('8')
|
|
>>> template.save()
|
|
>>> product, = template.products
|
|
|
|
Create purchase requisition without product and description::
|
|
|
|
>>> set_user(requisition_user)
|
|
>>> PurchaseRequisition = Model.get('purchase.requisition')
|
|
>>> requisition = PurchaseRequisition()
|
|
>>> requisition.description = 'Description'
|
|
>>> requisition.employee = employee
|
|
>>> requisition.supply_date = today
|
|
>>> requisition_line = requisition.lines.new()
|
|
>>> requisition_line.product = None
|
|
>>> requisition_line.description = None
|
|
>>> requisition_line.supplier = supplier
|
|
>>> requisition_line.unit_price = Decimal('10')
|
|
>>> requisition.click('wait') # doctest: +IGNORE_EXCEPTION_DETAIL
|
|
Traceback (most recent call last):
|
|
...
|
|
RequiredValidationError: ...
|
|
|
|
Create purchase requisition without product and quantity::
|
|
|
|
>>> requisition_line.description = 'Description'
|
|
>>> requisition.click('wait') # doctest: +IGNORE_EXCEPTION_DETAIL
|
|
Traceback (most recent call last):
|
|
...
|
|
RequiredValidationError: ...
|
|
|
|
Create purchase requisition with product goods and without warehouse::
|
|
|
|
>>> requisition.warehouse = None
|
|
>>> requisition_line.product = product
|
|
>>> requisition_line.description = 'Requisition Test'
|
|
>>> requisition_line.quantity = 2.0
|
|
>>> requisition.click('wait') # doctest: +IGNORE_EXCEPTION_DETAIL
|
|
Traceback (most recent call last):
|
|
...
|
|
RequiredValidationError: ...
|
|
|
|
Create purchase requisition with supplier and price::
|
|
|
|
>>> Location = Model.get('stock.location')
|
|
>>> warehouse_loc, = Location.find([('code', '=', 'WH')])
|
|
>>> requisition.warehouse = warehouse_loc
|
|
>>> requisition.click('wait')
|
|
>>> requisition.state
|
|
'waiting'
|
|
|
|
Approve workflow by requisition user raise an exception because he's not in
|
|
approval_group::
|
|
|
|
>>> set_user(requisition_user)
|
|
>>> requisition.click('approve') # doctest: +IGNORE_EXCEPTION_DETAIL
|
|
Traceback (most recent call last):
|
|
...
|
|
AccessButtonError: ...
|
|
|
|
Approve workflow by purchaser raise an exception because he's not in
|
|
approval_group::
|
|
|
|
>>> set_user(purchase_user)
|
|
>>> requisition.click('approve') # doctest: +IGNORE_EXCEPTION_DETAIL
|
|
Traceback (most recent call last):
|
|
...
|
|
AccessButtonError: ...
|
|
|
|
Approve workflow with user in approval_group::
|
|
|
|
>>> set_user(requisition_approval_user)
|
|
>>> requisition.click('approve')
|
|
>>> requisition.state
|
|
'processing'
|
|
>>> requisition.total_amount
|
|
Decimal('20.00')
|
|
|
|
Create Purchase order from Request::
|
|
|
|
>>> set_user(purchase_user)
|
|
>>> PurchaseRequest = Model.get('purchase.request')
|
|
>>> pr, = PurchaseRequest.find([('state', '=', 'draft')])
|
|
>>> pr.state
|
|
'draft'
|
|
>>> pr.product == product
|
|
True
|
|
>>> pr.party == supplier
|
|
True
|
|
>>> pr.quantity
|
|
2.0
|
|
>>> pr.computed_quantity
|
|
2.0
|
|
>>> pr.supply_date == today
|
|
True
|
|
>>> pr.warehouse == warehouse_loc
|
|
True
|
|
>>> create_purchase = Wizard('purchase.request.create_purchase', [pr])
|
|
>>> pr.state
|
|
'purchased'
|
|
>>> requisition.state
|
|
'processing'
|
|
|
|
Cancel the purchase order::
|
|
|
|
>>> Purchase = Model.get('purchase.purchase')
|
|
>>> purchase, = Purchase.find([('state', '=', 'draft')])
|
|
>>> purchase.click('cancel')
|
|
>>> purchase.state
|
|
'cancelled'
|
|
>>> pr.reload()
|
|
>>> pr.state
|
|
'exception'
|
|
>>> requisition.reload()
|
|
>>> requisition.state
|
|
'done'
|
|
|
|
Handle request exception::
|
|
|
|
>>> handle_exception = Wizard(
|
|
... 'purchase.request.handle.purchase.cancellation', [pr])
|
|
>>> handle_exception.execute('reset')
|
|
>>> pr.state
|
|
'draft'
|
|
>>> requisition.reload()
|
|
>>> requisition.state
|
|
'processing'
|
|
>>> create_purchase = Wizard('purchase.request.create_purchase', [pr])
|
|
>>> pr.state
|
|
'purchased'
|
|
>>> requisition.reload()
|
|
>>> requisition.state
|
|
'processing'
|
|
|
|
Confirm the purchase order::
|
|
|
|
>>> purchase, = Purchase.find([('state', '=', 'draft')])
|
|
>>> purchase_line, = purchase.lines
|
|
>>> purchase_line.unit_price
|
|
Decimal('10.0000')
|
|
>>> purchase.click('quote')
|
|
>>> requisition.reload()
|
|
>>> requisition.state
|
|
'processing'
|
|
>>> purchase.click('confirm')
|
|
>>> purchase.reload()
|
|
>>> purchase.state
|
|
'processing'
|
|
>>> requisition.reload()
|
|
>>> requisition.state
|
|
'done'
|
|
|
|
Try to delete requisition done::
|
|
|
|
>>> set_user(requisition_user)
|
|
>>> PurchaseRequisition.delete([requisition]) # doctest: +IGNORE_EXCEPTION_DETAIL
|
|
Traceback (most recent call last):
|
|
...
|
|
AccessError: ...
|
|
|
|
Delete draft requisition::
|
|
|
|
>>> requisition = PurchaseRequisition()
|
|
>>> requisition.employee = employee
|
|
>>> requisition.supply_date = today
|
|
>>> requisition.save()
|
|
>>> PurchaseRequisition.delete([requisition])
|
|
|
|
Create purchase requisition with two different suppliers::
|
|
|
|
>>> set_user(requisition_user)
|
|
>>> requisition = PurchaseRequisition()
|
|
>>> requisition.description = 'Description'
|
|
>>> requisition.employee = employee
|
|
>>> requisition.supply_date = today
|
|
>>> requisition_line = requisition.lines.new()
|
|
>>> requisition_line.description = 'Description'
|
|
>>> requisition_line.quantity = 4.0
|
|
>>> requisition_line.supplier = supplier
|
|
>>> requisition_line = requisition.lines.new()
|
|
>>> requisition_line.description = 'Description2'
|
|
>>> requisition_line.quantity = 2.0
|
|
>>> requisition_line.supplier = supplier2
|
|
>>> requisition.click('wait')
|
|
|
|
>>> set_user(requisition_approval_user)
|
|
>>> requisition.click('approve')
|
|
|
|
>>> set_user(purchase_user)
|
|
>>> pr = PurchaseRequest.find([('state', '=', 'draft')])
|
|
>>> len(pr)
|
|
2
|
|
>>> pr[0].party == supplier2
|
|
True
|
|
>>> pr[1].party == supplier
|
|
True
|
|
>>> create_purchase = Wizard('purchase.request.create_purchase', pr)
|
|
>>> purchase, = Purchase.find([
|
|
... ('state', '=', 'draft'),
|
|
... ('party', '=', supplier.id),
|
|
... ])
|
|
>>> purchase.click('cancel')
|
|
>>> requisition.reload()
|
|
>>> requisition.state
|
|
'processing'
|
|
>>> purchase, = Purchase.find([
|
|
... ('state', '=', 'draft'),
|
|
... ('party', '=', supplier2.id),
|
|
... ])
|
|
>>> purchase.click('quote')
|
|
>>> purchase.click('confirm')
|
|
>>> requisition.reload()
|
|
>>> requisition.state
|
|
'done'
|
|
|
|
Create purchase requisition then cancel::
|
|
|
|
>>> set_user(requisition_user)
|
|
>>> requisition = PurchaseRequisition()
|
|
>>> requisition.description = 'Description'
|
|
>>> requisition.employee = employee
|
|
>>> requisition.supply_date = today
|
|
>>> requisition_line = requisition.lines.new()
|
|
>>> requisition_line.description = 'Description'
|
|
>>> requisition_line.quantity = 4.0
|
|
>>> requisition.click('cancel')
|
|
>>> requisition.state
|
|
'cancelled'
|
|
|
|
Create purchase requisition, wait then reject::
|
|
|
|
>>> set_user(requisition_user)
|
|
>>> requisition = PurchaseRequisition()
|
|
>>> requisition.description = 'Description'
|
|
>>> requisition.employee = employee
|
|
>>> requisition.supply_date = today
|
|
>>> requisition_line = requisition.lines.new()
|
|
>>> requisition_line.description = 'Description'
|
|
>>> requisition_line.quantity = 4.0
|
|
>>> requisition.click('wait')
|
|
>>> requisition.state
|
|
'waiting'
|
|
|
|
>>> set_user(requisition_approval_user)
|
|
>>> requisition.click('reject')
|
|
>>> requisition.state
|
|
'rejected'
|