Add demo script
@@ -339,4 +339,25 @@ test-sao:
|
||||
PACKAGE: 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'
|
||||
|
||||
@@ -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)
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -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
|
||||
@@ -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')
|
||||
@@ -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()
|
||||
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 17 KiB |
@@ -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
|
||||
@@ -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]
|
||||
@@ -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]
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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()
|
||||
@@ -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))
|
||||
@@ -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))
|
||||
@@ -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')
|
||||
@@ -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)
|
||||
@@ -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()
|
||||