Add demo script

This commit is contained in:
Cédric Krier
2024-04-28 13:58:17 +02:00
parent 5f5a93617d
commit a9a5be0834
29 changed files with 1197 additions and 0 deletions
+21
View File
@@ -339,4 +339,25 @@ test-sao:
PACKAGE: sao PACKAGE: sao
TAG_PATTERN: '/^sao-.*/' TAG_PATTERN: '/^sao-.*/'
test-demo:
stage: test
image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/python:3.8
variables:
TRYTOND_DATABASE__PATH: /tmp
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
cache:
paths:
- .cache/pip/http
before_script:
- pip install packages/trytond* packages/proteus*
script:
- touch /tmp/demo.sqlite
- echo "admin" > /tmp/password
- TRYTONPASSFILE=/tmp/password trytond-admin --database demo --all --email admin@example.com
- python -m demo --database demo
rules:
- changes:
- demo/**/*
- modules/{account,account_invoice,account_payment,account_statement,company,country,currency,party,product,production,production_routing,production_work,project,purchase,sale,stock,timesheet}/**/*
include: '.gitlab-ci-modules.yml' include: '.gitlab-ci-modules.yml'
+182
View File
@@ -0,0 +1,182 @@
#!/usr/bin/env python3
# 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 argparse import ArgumentDefaultsHelpFormatter, ArgumentParser
from proteus import Model, Wizard
from proteus import config as pconfig
from . import account, account_invoice, account_payment, account_statement
from . import company as company_
from . import (
country, currency, party, product, production, project, purchase, sale,
stock, timesheet)
def set_config(database, config_file):
return pconfig.set_trytond(database, config_file=config_file)
def activate_modules(config, modules):
Module = Model.get('ir.module')
modules = Module.find([
('name', 'in', modules),
])
for module in modules:
if module.state == 'activated':
module.click('upgrade')
else:
module.click('activate')
modules = [x.name for x in Module.find([('state', '=', 'to activate')])]
Wizard('ir.module.activate_upgrade').execute('upgrade')
ConfigWizardItem = Model.get('ir.module.config_wizard.item')
for item in ConfigWizardItem.find([('state', '!=', 'done')]):
item.state = 'done'
item.save()
activated_modules = [m.name
for m in Module.find([('state', '=', 'activated')])]
return modules, activated_modules
def setup_languages(config, demo_password, company=None):
Lang = Model.get('ir.lang')
User = Model.get('res.user')
Group = Model.get('res.group')
Action = Model.get('ir.action')
langs = Lang.find()
Lang.click(langs, 'load_translations')
admin = config.user
# Use root to skip password validation
config.user = 0
menu, = Action.find([('usage', '=', 'menu')])
for lang in langs:
if lang.code == 'en':
name = 'Demo'
login = 'demo'
else:
if lang.code[:2] != lang.code[-2:].lower():
continue
name = 'Demo %s' % lang.name
login = 'demo_%s' % lang.code[:2]
try:
user, = User.find([('login', '=', login)])
except ValueError:
user = User()
user.name = name
user.login = login
user.password = demo_password
groups = Group.find([
('name', 'not ilike', '%Admin%'),
])
user.groups.extend(groups)
user.language = lang
user.menu = menu
if company:
Company = Model.get('company.company')
user.companies.append(Company(company.id))
user.company = company
user.save()
config.user = admin
def main(database, modules, demo_password, config_file=None):
config = set_config(database, config_file)
to_activate, activated = activate_modules(config, modules)
if 'country' in to_activate:
country.do_import()
if 'currency' in to_activate:
currency.do_import()
if ('party' in to_activate
or 'sale' in to_activate
or 'purchase' in to_activate
or 'stock' in activated):
customers, suppliers = party.setup(config, modules)
if 'company' in to_activate:
company = company_.setup(config, activated)
elif 'company' in activated:
company = company.get()
else:
company = None
if 'account' in to_activate:
account.setup(config, activated, company)
if 'company' in to_activate:
company_.setup_post(config, activated, company)
if 'product' in to_activate:
product.setup(config, activated, company=company)
if 'account_invoice' in to_activate:
account_invoice.setup(config, activated, company)
if 'sale' in to_activate:
sale.setup(config, activated, company, customers)
if 'purchase' in to_activate:
purchase.setup(config, activated, company, suppliers)
if 'stock' in to_activate:
stock.setup(config, activated, company, suppliers)
if 'account_invoice' in activated:
account_invoice.setup_post(config, activated, company)
if 'account_payment' in activated:
account_payment.setup(config, activated, company)
if 'account_statement' in activated:
account_statement.setup(config, activated, company)
if 'project' in activated:
project.setup(config, activated, company, customers)
if 'timesheet' in activated:
timesheet.setup(config, activated, company)
if 'production' in to_activate:
production.setup(config, activated, company)
setup_languages(config, demo_password, company=company)
if __name__ == '__main__':
parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)
parser.add_argument('-c', '--config', dest='config_file')
parser.add_argument('-m', '--module', dest='modules', nargs='+',
help='module to activate', default=[
'account',
'account_invoice',
'account_payment',
'account_statement',
'company',
'party',
'party_avatar',
'product',
'purchase',
'sale',
'stock',
'project',
'timesheet',
'production',
'production_routing',
'production_work',
])
parser.add_argument('--demo_password', dest='demo_password',
default='demo', help='demo password')
parser.add_argument('-d', '--database', dest='database',
default='demo', help="database name")
options = parser.parse_args()
main(options.database, options.modules, options.demo_password,
config_file=options.config_file)
+82
View File
@@ -0,0 +1,82 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import datetime as dt
from dateutil.relativedelta import relativedelta
from proteus import Model, Wizard
def setup(config, modules, company):
AccountTemplate = Model.get('account.account.template')
Account = Model.get('account.account')
FiscalYear = Model.get('account.fiscalyear')
Sequence = Model.get('ir.sequence')
SequenceStrict = Model.get('ir.sequence.strict')
SequenceType = Model.get('ir.sequence.type')
Party = Model.get('party.party')
root_template, = AccountTemplate.find([
('parent', '=', None),
('name', '=', 'Minimal Account Chart'),
])
create_chart_account = Wizard('account.create_chart')
create_chart_account.execute('account')
create_chart_account.form.account_template = root_template
create_chart_account.form.company = company
create_chart_account.execute('create_account')
receivable, = Account.find([
('type.receivable', '=', True),
('company', '=', company.id),
])
payable, = Account.find([
('type.payable', '=', True),
('company', '=', company.id),
])
create_chart_account.form.account_receivable = receivable
create_chart_account.form.account_payable = payable
create_chart_account.execute('create_properties')
# Set account for parties created without company
parties = Party.find([])
for party in parties:
party.account_receivable = receivable
party.account_payable = payable
Party.save(parties)
move_sequence_type, = SequenceType.find(
[('name', '=', "Account Move")], limit=1)
invoice_sequence_type, = SequenceType.find([
('name', '=', "Invoice"),
], limit=1)
today = dt.date.today()
for start_date in (
today + relativedelta(month=1, day=1, years=-1),
today + relativedelta(month=1, day=1),
today + relativedelta(month=1, day=1, years=1)):
fiscalyear = FiscalYear(name='%s' % start_date.year)
fiscalyear.start_date = start_date
fiscalyear.end_date = start_date + relativedelta(month=12, day=31)
fiscalyear.company = company
post_move_sequence = Sequence(name='%s' % start_date.year,
sequence_type=move_sequence_type,
company=company)
post_move_sequence.save()
fiscalyear.post_move_sequence = post_move_sequence
invoice_sequence, = fiscalyear.invoice_sequences
if 'account_invoice' in modules:
for attr, name in (('out_invoice_sequence', 'Invoice'),
('in_invoice_sequence', 'Supplier Invoice'),
('out_credit_note_sequence', 'Credit Note'),
('in_credit_note_sequence', 'Supplier Credit Note')):
sequence = SequenceStrict(
name='%s %s' % (name, start_date.year),
sequence_type=invoice_sequence_type,
company=company)
sequence.save()
setattr(invoice_sequence, attr, sequence)
fiscalyear.save()
fiscalyear.click('create_period')
+61
View File
@@ -0,0 +1,61 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import datetime as dt
import random
from itertools import chain
from dateutil.relativedelta import relativedelta
from proteus import Model
from .tools import skip_warning
def setup(config, modules, company):
Party = Model.get('party.party')
PaymentTerm = Model.get('account.invoice.payment_term')
payment_term = PaymentTerm(name='30 days')
line = payment_term.lines.new()
line.type = 'remainder'
delta = line.relativedeltas.new()
delta.days = 30
payment_term.save()
parties = Party.find()
Party.write([p.id for p in parties], {
'customer_payment_term': payment_term.id,
'supplier_payment_term': payment_term.id,
}, config.context)
def setup_post(config, modules, company):
Invoice = Model.get('account.invoice')
invoices = Invoice.find([
('type', '=', 'out'),
('state', 'in', ['draft', 'validated']),
])
invoices = random.sample(invoices, len(invoices) * 2 // 3)
invoices = list(chain(*list(zip(invoices,
Invoice.find([
('type', '=', 'in'),
('state', 'in', ['draft', 'validated']),
])))))
today = dt.date.today()
invoice_date = today + relativedelta(months=-1)
i = j = 0
while invoice_date <= today:
j = random.randint(1, 5)
for invoice in invoices[i:i + j]:
invoice.invoice_date = invoice_date
invoice.save()
i += j
invoice_date += relativedelta(days=random.randint(1, 3))
invoices = [inv for inv in invoices[0:i]]
for invoice in invoices:
skip_warning(config, 'invoice_payment_term', [invoice])
skip_warning(config, 'invoice_date_future', invoices)
Invoice.click(invoices, 'post')
+46
View File
@@ -0,0 +1,46 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import random
from proteus import Model, Wizard
def setup(config, modules, company):
Currency = Model.get('currency.currency')
Journal = Model.get('account.payment.journal')
Line = Model.get('account.move.line')
Payment = Model.get('account.payment')
usd, = Currency.find([('code', '=', 'USD')])
journal = Journal(name='Manual', currency=usd, company=company,
process_method='manual')
journal.save()
lines = Line.find([
('account.type.payable', '=', True),
('party', '!=', None),
('reconciliation', '=', None),
('payment_amount', '!=', 0),
])
lines = random.sample(lines, len(lines) * 2 // 3)
if not lines:
return
pay_line = Wizard('account.move.line.pay', lines)
pay_line.execute('next_')
pay_line.form.journal = journal
pay_line.execute('next_')
payments = Payment.find([])
payments = random.sample(payments, len(payments) * 2 // 3)
for payment in payments:
payment.click('approve')
payments = random.sample(payments, len(payments) * 2 // 3)
i = j = 0
while i < len(payments):
j = random.randint(1, 5)
Wizard('account.payment.process', payments[i:i + j])
i += j
+69
View File
@@ -0,0 +1,69 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import random
from decimal import Decimal
from dateutil.relativedelta import relativedelta
from proteus import Model
def setup(config, modules, company):
Journal = Model.get('account.statement.journal')
Statement = Model.get('account.statement')
AccountJournal = Model.get('account.journal')
Account = Model.get('account.account')
Sequence = Model.get('ir.sequence')
SequenceType = Model.get('ir.sequence.type')
Invoice = Model.get('account.invoice')
sequence_type, = SequenceType.find([('name', '=', "Account Journal")])
sequence = Sequence(name='Statement',
sequence_type=sequence_type,
company=company)
sequence.save()
cash, = Account.find([
('name', '=', 'Main Cash'),
('company', '=', company.id),
])
account_journal = AccountJournal(name='Bank',
type='statement',
sequence=sequence)
account_journal.save()
journal = Journal(name='Bank',
journal=account_journal,
account=cash,
validation='balance')
journal.save()
invoices = Invoice.find([
('state', '=', 'posted'),
])
invoices = random.sample(invoices, len(invoices) * 2 // 3)
total_amount = Decimal(0)
statement = Statement(name='001',
journal=journal,
start_balance=Decimal(0))
for i, invoice in enumerate(invoices):
if not invoice.amount_to_pay:
continue
line = statement.lines.new()
line.number = str(i)
line.date = invoice.invoice_date + relativedelta(
days=random.randint(1, 20))
amount = invoice.amount_to_pay
if invoice.type in ('in_invoice', 'out_credit_note'):
amount = - amount
line.amount = amount
line.party = invoice.party
if random.random() < 2. / 3.:
line.related_to = invoice
total_amount += line.amount
statement.end_balance = total_amount
statement.click('validate_statement')
+11
View File
@@ -0,0 +1,11 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import os
_AVATAR_DIR = os.path.join(os.path.dirname(__file__), 'avatars')
def get(name):
with open(os.path.join(_AVATAR_DIR, name), 'rb') as fp:
return fp.read()
Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

+134
View File
@@ -0,0 +1,134 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import datetime as dt
from decimal import Decimal
from proteus import Model, Wizard
from . import avatar
def setup(config, modules):
Party = Model.get('party.party')
Company = Model.get('company.company')
Currency = Model.get('currency.currency')
usd, = Currency.find([('code', '=', 'USD')])
rate = usd.rates.new()
rate.date = dt.date(dt.date.today().year, 1, 1)
rate.rate = Decimal('1')
usd.save()
company_config = Wizard('company.company.config')
company_config.execute('company')
company = company_config.form
party = Party(name='Michael Scott Paper Company')
if 'party_avatar' in modules:
party.avatar = avatar.get('michael-scott-paper-inc.jpg')
party.save()
company.party = party
company.currency = usd
company_config.execute('add')
# Reload context
User = Model.get('res.user')
config._context = User.get_preferences(True, {})
company, = Company.find()
return company
def setup_post(config, modules, company):
Party = Model.get('party.party')
Company = Model.get('company.company')
Currency = Model.get('currency.currency')
Address = Model.get('party.address')
Country = Model.get('country.country')
Subdivision = Model.get('country.subdivision')
Employee = Model.get('company.employee')
party_avatar = 'party_avatar' in modules
usd, = Currency.find([('code', '=', 'USD')])
try:
us, = Country.find([('code', '=', 'US')])
except ValueError:
us = None
party_scott = Party(name='Michael Scott')
if party_avatar:
party_scott.avatar = avatar.get('michael-scott.jpg')
party_scott.save()
Employee(party=party_scott, company=company).save()
party_beesly = Party(name='Pam Beesly')
if party_avatar:
party_beesly.avatar = avatar.get('pam-beesly.jpg')
party_beesly.save()
Employee(party=party_beesly, company=company).save()
party_howard = Party(name='Ryan Howard')
if party_avatar:
party_howard.avatar = avatar.get('ryan-howard.jpg')
party_howard.save()
Employee(party=party_howard, company=company).save()
dmi = Company()
party_dmi = Party(name='Dunder Mifflin inc')
address = Address()
party_dmi.addresses.append(address)
address.city = 'New York'
address.country = us
try:
address.subdivision, = Subdivision.find([('code', '=', 'US-NY')])
except ValueError:
pass
if party_avatar:
party_dmi.avatar = avatar.get('dunder-mifflin.jpg')
party_dmi.save()
dmi.party = party_dmi
dmi.currency = usd
dmi.save()
dms = Company()
party_dms = Party(name='Dunder Mifflin Scranton')
address = Address()
party_dms.addresses.append(address)
address.city = 'Scranton'
address.country = us
try:
address.subdivision, = Subdivision.find([('code', '=', 'US-PA')])
except ValueError:
pass
party_dms.save()
dms.party = party_dms
dms.currency = usd
dms.save()
party_halper = Party(name='Jim Halper')
if party_avatar:
party_halper.avatar = avatar.get('jim-halper.jpg')
party_halper.save()
Employee(party=party_halper, company=dms).save()
party_schrute = Party(name='Dwight Schrute')
if party_avatar:
party_schrute.avatar = avatar.get('dwight-schrute.jpg')
party_schrute.save()
Employee(party=party_schrute, company=dms).save()
party_martin = Party(name='Angela Martin')
if party_avatar:
party_martin.avatar = avatar.get('angela-martin.jpg')
party_martin.save()
Employee(party=party_martin, company=dms).save()
party_miner = Party(name='Charles Miner')
if party_avatar:
party_miner.avatar = avatar.get('charles-miner.jpg')
party_miner.save()
Employee(party=party_miner, company=dms).save()
def get():
Company = Model.get('company.company')
company, = Company.find([
('party.name', '=', 'Michael Scott Paper Company'),
])
return company
+10
View File
@@ -0,0 +1,10 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
try:
from trytond.modules.country.scripts.import_countries import do_import
except ImportError:
def do_import(*args, **kwargs):
pass
__all__ = [do_import]
+14
View File
@@ -0,0 +1,14 @@
# 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 proteus import Model
try:
from trytond.modules.currency.scripts.import_currencies import do_import
except ImportError:
def do_import(*args, **kwargs):
Currency = Model.get('currency.currency')
usd = Currency(name="USD", code='USD')
usd.save()
__all__ = [do_import]
+83
View File
@@ -0,0 +1,83 @@
# 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 proteus import Model
from . import avatar
def setup(config, modules):
Party = Model.get('party.party')
Address = Model.get('party.address')
Country = Model.get('country.country')
Subdivision = Model.get('country.subdivision')
ContactMechanism = Model.get('party.contact_mechanism')
customers, suppliers = [], []
try:
us, = Country.find([('code', '=', 'US')])
except ValueError:
us = None
try:
pennsylvania, = Subdivision.find([('code', '=', 'US-PA')])
except ValueError:
pennsylvania = None
name = 'Electric City Trolley Museum Association'
try:
party, = Party.find([('name', '=', name)])
except ValueError:
party = Party(name=name)
party.addresses.pop()
party.addresses.append(Address(street='300 Cliff Street',
postal_code='18503', city='Scranton', country=us,
subdivision=pennsylvania))
party.contact_mechanisms.append(ContactMechanism(type='phone',
value='+1 570-963-6590'))
party.contact_mechanisms.append(ContactMechanism(type='website',
value='http://www.ectma.org/'))
party.save()
customers.append(party)
name = 'Albright Memorial Library'
try:
party, = Party.find([('name', '=', name)])
except ValueError:
party = Party(name=name)
party.addresses.pop()
party.addresses.append(Address(street='500 Vine Street',
postal_code='18509', city='Scranton', country=us,
subdivision=pennsylvania))
party.contact_mechanisms.append(ContactMechanism(type='phone',
value='+1 570-348-3000'))
party.contact_mechanisms.append(ContactMechanism(type='website',
value='http://www.albright.org/'))
party.save()
customers.append(party)
name = "Cooper's Seafood House"
try:
party, = Party.find([('name', '=', name)])
except ValueError:
party = Party(name=name)
party.addresses.pop()
party.addresses.append(Address(street='701 North Washington Avenue',
postal_code='18509', city='Scranton', country=us,
subdivision=pennsylvania))
party.contact_mechanisms.append(ContactMechanism(type='phone',
value='+1 570-346-6883'))
party.save()
customers.append(party)
name = "Saber"
try:
party, = Party.find([('name', '=', name)])
except ValueError:
party = Party(name=name)
if 'party_avatar' in modules:
party.avatar = avatar.get('saber.jpg')
party.save()
suppliers.append(party)
return customers, suppliers
+62
View File
@@ -0,0 +1,62 @@
# 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 proteus import Model
def setup(config, modules, company=None):
ProductTemplate = Model.get('product.template')
Category = Model.get('product.category')
Uom = Model.get('product.uom')
if 'account_product' in modules:
Account = Model.get('account.account')
expense, = Account.find([
('type.expense', '=', True),
('company', '=', company.id),
])
revenue, = Account.find([
('type.revenue', '=', True),
('company', '=', company.id),
])
account_category = Category(name="Papers", accounting=True)
account_category.account_expense = expense
account_category.account_revenue = revenue
account_category.save()
papers = Category(name='Papers')
papers.save()
sizes = {}
for format in ['A5', 'A4', 'A3', 'Letter', 'Legal', 'Ledger']:
size = Category(name=format, parent=papers)
if 'account_product' in modules:
size.account_expense = expense
size.account_revenue = revenue
size.save()
sizes[format] = size
unit, = Uom.find([('name', '=', 'Unit')])
margin = Decimal('1.01')
for quantity in [250, 500]:
for format, category in sizes.items():
paper_template = ProductTemplate(name='%s Paper %s'
% (format, quantity))
paper_template.categories.append(Category(category.id))
if 'account_product' in modules:
paper_template.account_category = account_category
paper_template.default_uom = unit
paper_template.type = 'goods'
paper_template.list_price = (Decimal('0.02') * quantity * margin
).quantize(Decimal('0.0001'))
paper, = paper_template.products
paper.cost_price = Decimal('0.01') * quantity
if 'sale' in modules:
paper_template.salable = True
if 'purchase' in modules:
paper_template.purchasable = True
paper_template.save()
margin *= margin
+216
View File
@@ -0,0 +1,216 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import datetime as dt
import random
from decimal import Decimal
from dateutil.relativedelta import relativedelta
from proteus import Model
def setup(config, activated, company):
BOM = Model.get('production.bom')
Production = Model.get('production')
ProductTemplate = Model.get('product.template')
Category = Model.get('product.category')
Uom = Model.get('product.uom')
unit, = Uom.find([('name', '=', 'Unit')])
if 'account_product' in activated:
Account = Model.get('account.account')
expense, = Account.find([
('type.expense', '=', True),
('company', '=', company.id),
])
revenue, = Account.find([
('type.revenue', '=', True),
('company', '=', company.id),
])
account_category = Category(name="Computers", accounting=True)
account_category.account_expense = expense
account_category.account_revenue = revenue
account_category.save()
def create_product(name, list_price, cost_price):
template = ProductTemplate(name=name)
template.default_uom = unit
template.type = 'goods'
template.list_price = list_price
template.cost_price = cost_price
if 'account_product' in activated:
template.account_category = account_category
template.save()
return template.products[0]
bom = BOM(name='Computer rev1')
input_ = bom.inputs.new()
tower = create_product('Tower', Decimal(400), Decimal(250))
input_.product = tower
input_.quantity = 1
input_ = bom.inputs.new()
input_.product = create_product('Keyboard', Decimal(30), Decimal(10))
input_.quantity = 1
input_ = bom.inputs.new()
input_.product = create_product('Mouse', Decimal(10), Decimal(5))
input_.quantity = 1
input_ = bom.inputs.new()
input_.product = create_product('Screen', Decimal(300), Decimal(200))
input_.quantity = 1
output = bom.outputs.new()
computer = create_product('Computer', Decimal(750), Decimal(465))
computer.template.producible = True
computer.template.save()
output.product = computer
output.quantity = 1
bom.save()
computer.boms.new(bom=bom)
computer.save()
if 'production_routing' in activated:
setup_routing(config, activated, company)
if 'production_work' in activated:
WorkCenter = Model.get('production.work.center')
WorkCycle = Model.get('production.work.cycle')
setup_production_work(config, activated, company)
work_centers = WorkCenter.find([('parent', '=', None)])
today = dt.date.today()
production_date = today + relativedelta(months=-1)
while production_date <= today + relativedelta(days=20):
for _ in range(random.randint(0, 3)):
production = Production()
production.effective_date = production_date
production.product = computer
production.quantity = random.randint(1, 40)
production.bom = computer.boms[0].bom
if 'production_routing' in activated:
production.routing = computer.boms[0].routing
if 'production_work' in activated:
production.work_center = random.choice(work_centers)
production.save()
if (production_date < today) or (random.random() <= 1. / 3.):
production.click('wait')
if production_date < today:
production.click('assign_force')
production.click('run')
if random.random() <= 2. / 3.:
if 'production_work' in activated:
for work in production.works:
for _ in range(0, random.randint(1, 2)):
cycle = WorkCycle(
work=work,
duration=dt.timedelta(
seconds=random.randint(60, 3600)),
)
cycle.save()
cycle.click('run')
cycle.click('do')
output, = production.outputs
output.unit_price = (production.cost
/ Decimal(production.quantity)
).quantize(Decimal('0.0001'))
production.click('do')
production_date += relativedelta(days=random.randint(1, 3))
def setup_routing(config, activated, company):
Routing = Model.get('production.routing')
Operation = Model.get('production.routing.operation')
Product = Model.get('product.product')
routing = Routing(name='Computer routing rev1')
operation1 = Operation(name='Assemble pieces')
operation1.save()
step1 = routing.steps.new()
step1.operation = operation1
operation2 = Operation(name='Install software')
operation2.save()
step2 = routing.steps.new()
step2.operation = operation2
operation3 = Operation(name='Test')
operation3.save()
step3 = routing.steps.new()
step3.operation = operation3
operation4 = Operation(name='Package')
operation4.save()
step4 = routing.steps.new()
step4.operation = operation4
routing.boms.extend(routing.boms.find([('name', '=', 'Computer rev1')]))
routing.save()
computer, = Product.find([('name', '=', 'Computer')])
bom, = computer.boms
bom.routing = routing
bom.save()
def setup_production_work(config, activated, company):
WorkCenterCategory = Model.get('production.work.center.category')
WorkCenter = Model.get('production.work.center')
Operation = Model.get('production.routing.operation')
assembly = WorkCenterCategory(name='Assembly')
assembly.save()
operation, = Operation.find([('name', '=', 'Assemble pieces')])
operation.work_center_category = assembly
operation.save()
installation = WorkCenterCategory(name='Installation')
installation.save()
operations = Operation.find([
('name', 'in', ['Install software', 'Test']),
])
for operation in operations:
operation.work_center_category = installation
Operation.save(operations)
packaging = WorkCenterCategory(name='Packaging')
packaging.save()
operation, = Operation.find([('name', '=', 'Package')])
operation.work_center_category = packaging
operation.save()
lines = []
for i in range(1, 4):
line = WorkCenter(name='Line %i' % i)
assembly_line = line.children.new()
assembly_line.name = 'Assembly Line %i' % i
assembly_line.category = assembly
assembly_line.cost_method = 'cycle'
assembly_line.cost_price = Decimal(20)
installation_line = line.children.new()
installation_line.name = 'Installation Line %i' % i
installation_line.category = installation
installation_line.cost_method = 'hour'
installation_line.cost_price = Decimal(15)
packaging_line = line.children.new()
packaging_line.name = 'Packaging Line %i' % i
packaging_line.category = packaging
packaging_line.cost_method = 'hour'
packaging_line.cost_price = Decimal(10)
lines.append(line)
WorkCenter.save(lines)
+29
View File
@@ -0,0 +1,29 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import datetime as dt
import random
from proteus import Model
def setup(config, activated, company, customers):
Work = Model.get('project.work')
customer_projects = {
'Website': ['analysis', 'design', 'setup'],
'Labels': ['design'],
'Calendar': ['design'],
}
for name, task_names in customer_projects.items():
project = Work(name=name, type='project', timesheet_available=False)
project.party = random.choice(customers)
for task_name in task_names:
task = Work(name=task_name, type='task', timesheet_available=True)
task.effort_duration = dt.timedelta(
days=random.randint(10, 30),
hours=random.randint(1, 5))
task.progress = random.randint(1, 100) // 5 * 5 / 100.
project.children.append(task)
project.save()
+42
View File
@@ -0,0 +1,42 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import datetime as dt
import random
from dateutil.relativedelta import relativedelta
from proteus import Model
def setup(config, modules, company, suppliers):
Purchase = Model.get('purchase.purchase')
Product = Model.get('product.product')
all_products = Product.find([
('purchasable', '=', True),
])
today = dt.date.today()
purchase_date = today - relativedelta(days=60)
while purchase_date <= today + relativedelta(days=20):
supplier = random.choice(suppliers)
purchase = Purchase()
purchase.party = supplier
purchase.purchase_date = purchase_date
products = random.sample(
all_products, random.randint(1, len(all_products)))
for product in products:
purchase_line = purchase.lines.new()
purchase_line.product = product
purchase_line.quantity = random.randint(20, 100)
purchase_line.unit_price = product.cost_price
purchase.save()
threshold = 2. / 3.
if random.random() <= threshold:
purchase.click('quote')
if random.random() <= threshold:
purchase.click('confirm')
purchase.click('process')
elif random.choice([True, False]):
purchase.click('cancel')
purchase_date += relativedelta(days=random.randint(5, 10))
+48
View File
@@ -0,0 +1,48 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import datetime as dt
import random
from dateutil.relativedelta import relativedelta
from proteus import Model
def setup(config, modules, company, customers):
Sale = Model.get('sale.sale')
Product = Model.get('product.product')
all_products = Product.find([
('salable', '=', True),
])
today = dt.date.today()
sale_date = today + relativedelta(months=-2)
while sale_date <= today + relativedelta(days=10):
for _ in range(random.randint(1, 5)):
customer = random.choice(customers)
sale = Sale()
sale.party = customer
sale.sale_date = sale_date
products = random.sample(
all_products, random.randint(1, len(all_products)))
for product in products:
sale_line = sale.lines.new()
sale_line.product = product
sale_line.quantity = random.randint(1, 50)
sale.save()
if sale_date <= today:
threshold = 2. / 3.
else:
threshold = 1. / 3.
if random.random() <= threshold:
sale.click('quote')
if random.random() <= threshold:
sale.click('confirm')
if random.random() <= threshold:
sale.click('process')
elif random.random() >= threshold:
sale.click('cancel')
elif random.random() >= threshold:
sale.click('cancel')
sale_date += relativedelta(days=random.randint(1, 3))
+32
View File
@@ -0,0 +1,32 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import random
from proteus import Model
def setup(config, activated, company, suppliers):
ShipmentIn = Model.get('stock.shipment.in')
ShipmentOut = Model.get('stock.shipment.out')
for supplier in suppliers:
shipment = ShipmentIn()
shipment.supplier = supplier
all_moves = shipment.incoming_moves.find()
moves = random.sample(all_moves, len(all_moves) * 2 // 3)
while moves:
shipment = ShipmentIn()
shipment.supplier = supplier
for _ in range(random.randint(1, len(moves))):
move = moves.pop()
shipment.incoming_moves.append(move)
shipment.click('receive')
shipment.click('do')
shipments = ShipmentOut.find([('state', '=', 'waiting')])
for shipment in shipments:
if shipment.click('assign_try'):
shipment.click('pick')
shipment.click('pack')
shipment.click('do')
+39
View File
@@ -0,0 +1,39 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import datetime as dt
import random
from dateutil.relativedelta import relativedelta
from proteus import Model
def setup(config, activated, company):
Work = Model.get('timesheet.work')
Employee = Model.get('company.employee')
Line = Model.get('timesheet.line')
for name in ['Marketing', 'Accounting', 'Secretary']:
work = Work(name=name)
work.save()
employees = Employee.find([('company', '=', company.id)])
works = Work.find([])
today = dt.date.today()
date = today + relativedelta(months=-1)
day = dt.timedelta(hours=8)
while date <= today:
if date.weekday() < 5:
for employee in employees:
total = dt.timedelta()
while total < day:
if random.random() > 0.8:
break
line = Line(employee=employee, date=date)
line.work = random.choice(works)
duration = dt.timedelta(hours=random.randint(1, 8))
line.duration = min(duration, day - total)
line.save()
date += dt.timedelta(days=1)
+16
View File
@@ -0,0 +1,16 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import hashlib
from proteus import Model
def format_warning(name, records):
key = '|'.join(map(str, records)).encode('utf-8')
return '%s.%s' % (hashlib.md5(key).hexdigest(), name)
def skip_warning(config, name, records):
Warning_ = Model.get('res.user.warning')
Warning_(user=config.user, name=format_warning(name, records)).save()