Remove support for Python 2.7
issue7497 review53261002
This commit is contained in:
@@ -25,12 +25,6 @@ services:
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- IMAGE: python:2.7
|
||||
TOXENV: py27
|
||||
DATABASE: sqlite
|
||||
- IMAGE: python:2.7
|
||||
TOXENV: py27
|
||||
DATABASE: postgresql
|
||||
- IMAGE: python:3.4
|
||||
TOXENV: py34
|
||||
DATABASE: sqlite
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
* Remove support for Python 2.7
|
||||
* Invoice purchased product instead of received product
|
||||
* Prevent delete lines if purchase is not draft or canceled
|
||||
* Use today as fallback for purchase date report
|
||||
|
||||
@@ -4,7 +4,7 @@ Installing trytond_purchase
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
* Python 2.7 or later (http://www.python.org/)
|
||||
* Python 3.4 or later (http://www.python.org/)
|
||||
* trytond (http://www.tryton.org/)
|
||||
* python-sql 0.4 or later (http://code.google.com/p/python-sql/)
|
||||
* trytond_company (http://www.tryton.org/)
|
||||
|
||||
+2
-4
@@ -26,8 +26,7 @@ def process_purchase(func):
|
||||
return wrapper
|
||||
|
||||
|
||||
class Invoice:
|
||||
__metaclass__ = PoolMeta
|
||||
class Invoice(metaclass=PoolMeta):
|
||||
__name__ = 'account.invoice'
|
||||
purchase_exception_state = fields.Function(fields.Selection([
|
||||
('', ''),
|
||||
@@ -110,8 +109,7 @@ class Invoice:
|
||||
super(Invoice, cls).cancel(invoices)
|
||||
|
||||
|
||||
class InvoiceLine:
|
||||
__metaclass__ = PoolMeta
|
||||
class InvoiceLine(metaclass=PoolMeta):
|
||||
__name__ = 'account.invoice.line'
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -5,8 +5,7 @@ from trytond.pool import PoolMeta, Pool
|
||||
__all__ = ['PartyReplace', 'PartyErase']
|
||||
|
||||
|
||||
class PartyReplace:
|
||||
__metaclass__ = PoolMeta
|
||||
class PartyReplace(metaclass=PoolMeta):
|
||||
__name__ = 'party.replace'
|
||||
|
||||
@classmethod
|
||||
@@ -17,8 +16,7 @@ class PartyReplace:
|
||||
]
|
||||
|
||||
|
||||
class PartyErase:
|
||||
__metaclass__ = PoolMeta
|
||||
class PartyErase(metaclass=PoolMeta):
|
||||
__name__ = 'party.erase'
|
||||
|
||||
@classmethod
|
||||
|
||||
+2
-4
@@ -17,8 +17,7 @@ from trytond.modules.product import price_digits
|
||||
__all__ = ['Template', 'Product', 'ProductSupplier', 'ProductSupplierPrice']
|
||||
|
||||
|
||||
class Template:
|
||||
__metaclass__ = PoolMeta
|
||||
class Template(metaclass=PoolMeta):
|
||||
__name__ = "product.template"
|
||||
purchasable = fields.Boolean('Purchasable', states={
|
||||
'readonly': ~Eval('active', True),
|
||||
@@ -85,8 +84,7 @@ class Template:
|
||||
super(Template, cls).write(*args)
|
||||
|
||||
|
||||
class Product:
|
||||
__metaclass__ = PoolMeta
|
||||
class Product(metaclass=PoolMeta):
|
||||
__name__ = 'product.product'
|
||||
|
||||
purchase_price_uom = fields.Function(fields.Numeric(
|
||||
|
||||
+5
-8
@@ -65,7 +65,7 @@ def search_shipments_returns(model_name):
|
||||
return [('lines.moves.shipment' + nested,)
|
||||
+ tuple(clause[1:3]) + (model_name,) + tuple(clause[3:])]
|
||||
else:
|
||||
if isinstance(clause[2], basestring):
|
||||
if isinstance(clause[2], str):
|
||||
target = 'rec_name'
|
||||
else:
|
||||
target = 'id'
|
||||
@@ -471,7 +471,7 @@ class Purchase(Workflow, ModelSQL, ModelView, TaxableMixin):
|
||||
for line in self.lines:
|
||||
self.untaxed_amount += getattr(line, 'amount', None) or 0
|
||||
taxes = self._get_taxes()
|
||||
self.tax_amount = sum(t['amount'] for t in taxes.itervalues())
|
||||
self.tax_amount = sum(t['amount'] for t in taxes.values())
|
||||
if self.currency:
|
||||
self.untaxed_amount = self.currency.round(self.untaxed_amount)
|
||||
self.tax_amount = self.currency.round(self.tax_amount)
|
||||
@@ -498,7 +498,7 @@ class Purchase(Workflow, ModelSQL, ModelView, TaxableMixin):
|
||||
return taxable_lines
|
||||
|
||||
def get_tax_amount(self):
|
||||
taxes = self._get_taxes().itervalues()
|
||||
taxes = iter(self._get_taxes().values())
|
||||
return sum((tax['amount'] for tax in taxes), Decimal(0))
|
||||
|
||||
@classmethod
|
||||
@@ -538,7 +538,7 @@ class Purchase(Workflow, ModelSQL, ModelView, TaxableMixin):
|
||||
'tax_amount': tax_amount,
|
||||
'total_amount': total_amount,
|
||||
}
|
||||
for key in result.keys():
|
||||
for key in list(result.keys()):
|
||||
if key not in names:
|
||||
del result[key]
|
||||
return result
|
||||
@@ -1342,10 +1342,7 @@ class PurchaseLine(sequence_ordered(), ModelSQL, ModelView):
|
||||
dates = filter(
|
||||
None, (m.effective_date or m.planned_date for m in self.moves
|
||||
if m.state != 'cancel'))
|
||||
if dates:
|
||||
return min(dates)
|
||||
else:
|
||||
return
|
||||
return min(dates, default=None)
|
||||
delivery_date = None
|
||||
if self.delivery_date_edit:
|
||||
delivery_date = self.delivery_date_store
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
#!/usr/bin/env python
|
||||
#!/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 setuptools import setup
|
||||
import re
|
||||
import os
|
||||
import io
|
||||
try:
|
||||
from configparser import ConfigParser
|
||||
except ImportError:
|
||||
from ConfigParser import ConfigParser
|
||||
import os
|
||||
import re
|
||||
from configparser import ConfigParser
|
||||
from setuptools import setup
|
||||
|
||||
|
||||
def read(fname):
|
||||
@@ -27,6 +24,7 @@ def get_require_version(name):
|
||||
major_version, minor_version + 1)
|
||||
return require
|
||||
|
||||
|
||||
config = ConfigParser()
|
||||
config.readfp(open('tryton.cfg'))
|
||||
info = dict(config.items('tryton'))
|
||||
@@ -102,7 +100,6 @@ setup(name=name,
|
||||
'Natural Language :: Slovenian',
|
||||
'Natural Language :: Spanish',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
@@ -112,6 +109,7 @@ setup(name=name,
|
||||
'Topic :: Office/Business :: Financial :: Accounting',
|
||||
],
|
||||
license='GPL-3',
|
||||
python_requires='>=3.4',
|
||||
install_requires=requires,
|
||||
dependency_links=dependency_links,
|
||||
zip_safe=False,
|
||||
@@ -121,10 +119,5 @@ setup(name=name,
|
||||
""",
|
||||
test_suite='tests',
|
||||
test_loader='trytond.test_loader:Loader',
|
||||
use_2to3=True,
|
||||
convert_2to3_doctests=[
|
||||
'tests/scenario_purchase.rst',
|
||||
'tests/scenario_purchase_empty.rst',
|
||||
],
|
||||
tests_require=tests_require,
|
||||
)
|
||||
|
||||
@@ -15,8 +15,7 @@ from trytond.modules.product import price_digits
|
||||
__all__ = ['ShipmentIn', 'ShipmentInReturn', 'Move', 'Location']
|
||||
|
||||
|
||||
class ShipmentIn:
|
||||
__metaclass__ = PoolMeta
|
||||
class ShipmentIn(metaclass=PoolMeta):
|
||||
__name__ = 'stock.shipment.in'
|
||||
|
||||
@classmethod
|
||||
@@ -83,8 +82,7 @@ class ShipmentIn:
|
||||
return super(ShipmentIn, cls).draft(shipments)
|
||||
|
||||
|
||||
class ShipmentInReturn:
|
||||
__metaclass__ = PoolMeta
|
||||
class ShipmentInReturn(metaclass=PoolMeta):
|
||||
__name__ = 'stock.shipment.in.return'
|
||||
|
||||
@classmethod
|
||||
@@ -166,8 +164,7 @@ class ShipmentInReturn:
|
||||
return super(ShipmentInReturn, cls).draft(shipments)
|
||||
|
||||
|
||||
class Move:
|
||||
__metaclass__ = PoolMeta
|
||||
class Move(metaclass=PoolMeta):
|
||||
__name__ = 'stock.move'
|
||||
purchase = fields.Function(fields.Many2One('purchase.purchase', 'Purchase',
|
||||
states={
|
||||
@@ -355,8 +352,7 @@ class Move:
|
||||
Purchase.process(purchases)
|
||||
|
||||
|
||||
class Location:
|
||||
__metaclass__ = PoolMeta
|
||||
class Location(metaclass=PoolMeta):
|
||||
__name__ = 'stock.location'
|
||||
|
||||
supplier_return_location = fields.Many2One(
|
||||
|
||||
+43
-43
@@ -125,7 +125,7 @@ Create an Inventory::
|
||||
>>> inventory_line.expected_quantity = 0.0
|
||||
>>> inventory.click('confirm')
|
||||
>>> inventory.state
|
||||
u'done'
|
||||
'done'
|
||||
|
||||
Purchase 5 products::
|
||||
|
||||
@@ -157,11 +157,11 @@ Purchase 5 products::
|
||||
>>> purchase.untaxed_amount, purchase.tax_amount, purchase.total_amount
|
||||
(Decimal('25.00'), Decimal('2.50'), Decimal('27.50'))
|
||||
>>> purchase.state
|
||||
u'processing'
|
||||
'processing'
|
||||
>>> purchase.shipment_state
|
||||
u'waiting'
|
||||
'waiting'
|
||||
>>> purchase.invoice_state
|
||||
u'waiting'
|
||||
'waiting'
|
||||
>>> len(purchase.moves), len(purchase.shipment_returns), len(purchase.invoices)
|
||||
(2, 0, 1)
|
||||
>>> invoice, = purchase.invoices
|
||||
@@ -189,9 +189,9 @@ Post invoice and check no new invoices::
|
||||
>>> invoice.click('post')
|
||||
>>> purchase.reload()
|
||||
>>> purchase.shipment_state
|
||||
u'waiting'
|
||||
'waiting'
|
||||
>>> purchase.invoice_state
|
||||
u'waiting'
|
||||
'waiting'
|
||||
>>> len(purchase.moves), len(purchase.shipment_returns), len(purchase.invoices)
|
||||
(2, 0, 1)
|
||||
|
||||
@@ -217,11 +217,11 @@ Purchase 5 products with an invoice method 'on shipment'::
|
||||
>>> purchase.click('confirm')
|
||||
>>> purchase.click('process')
|
||||
>>> purchase.state
|
||||
u'processing'
|
||||
'processing'
|
||||
>>> purchase.shipment_state
|
||||
u'waiting'
|
||||
'waiting'
|
||||
>>> purchase.invoice_state
|
||||
u'none'
|
||||
'none'
|
||||
>>> len(purchase.moves), len(purchase.shipment_returns), len(purchase.invoices)
|
||||
(2, 0, 0)
|
||||
|
||||
@@ -250,17 +250,17 @@ Validate Shipments::
|
||||
>>> shipment.click('done')
|
||||
>>> purchase.reload()
|
||||
>>> purchase.shipment_state
|
||||
u'received'
|
||||
'received'
|
||||
>>> len(purchase.shipments), len(purchase.shipment_returns)
|
||||
(1, 0)
|
||||
|
||||
Open supplier invoice::
|
||||
|
||||
>>> purchase.invoice_state
|
||||
u'waiting'
|
||||
'waiting'
|
||||
>>> invoice, = purchase.invoices
|
||||
>>> invoice.type
|
||||
u'in'
|
||||
'in'
|
||||
>>> invoice_line1, invoice_line2 = sorted(invoice.lines,
|
||||
... key=lambda l: l.quantity or 0)
|
||||
>>> for line in invoice.lines:
|
||||
@@ -289,9 +289,9 @@ Create the report::
|
||||
>>> purchase_report = Report('purchase.purchase')
|
||||
>>> ext, _, _, name = purchase_report.execute([purchase], {})
|
||||
>>> ext
|
||||
u'odt'
|
||||
'odt'
|
||||
>>> name
|
||||
u'Purchase'
|
||||
'Purchase'
|
||||
|
||||
Create a Return::
|
||||
|
||||
@@ -311,11 +311,11 @@ Create a Return::
|
||||
>>> return_.click('confirm')
|
||||
>>> return_.click('process')
|
||||
>>> return_.state
|
||||
u'processing'
|
||||
'processing'
|
||||
>>> return_.shipment_state
|
||||
u'waiting'
|
||||
'waiting'
|
||||
>>> return_.invoice_state
|
||||
u'none'
|
||||
'none'
|
||||
>>> (len(return_.shipments), len(return_.shipment_returns),
|
||||
... len(return_.invoices))
|
||||
(0, 1, 0)
|
||||
@@ -325,30 +325,30 @@ Check Return Shipments::
|
||||
>>> ShipmentReturn = Model.get('stock.shipment.in.return')
|
||||
>>> ship_return, = return_.shipment_returns
|
||||
>>> ship_return.state
|
||||
u'waiting'
|
||||
'waiting'
|
||||
>>> move_return, = ship_return.moves
|
||||
>>> move_return.product.rec_name
|
||||
u'product'
|
||||
'product'
|
||||
>>> move_return.quantity
|
||||
4.0
|
||||
>>> ship_return.click('assign_try')
|
||||
True
|
||||
>>> ship_return.click('done')
|
||||
>>> ship_return.state
|
||||
u'done'
|
||||
'done'
|
||||
>>> return_.reload()
|
||||
>>> return_.state
|
||||
u'processing'
|
||||
'processing'
|
||||
>>> return_.shipment_state
|
||||
u'received'
|
||||
'received'
|
||||
>>> return_.invoice_state
|
||||
u'waiting'
|
||||
'waiting'
|
||||
|
||||
Open supplier credit note::
|
||||
|
||||
>>> credit_note, = return_.invoices
|
||||
>>> credit_note.type
|
||||
u'in'
|
||||
'in'
|
||||
>>> len(credit_note.lines)
|
||||
1
|
||||
>>> sum(l.quantity for l in credit_note.lines)
|
||||
@@ -378,11 +378,11 @@ Mixing return and purchase::
|
||||
>>> mix.click('confirm')
|
||||
>>> mix.click('process')
|
||||
>>> mix.state
|
||||
u'processing'
|
||||
'processing'
|
||||
>>> mix.shipment_state
|
||||
u'waiting'
|
||||
'waiting'
|
||||
>>> mix.invoice_state
|
||||
u'waiting'
|
||||
'waiting'
|
||||
>>> len(mix.moves), len(mix.shipment_returns), len(mix.invoices)
|
||||
(2, 1, 1)
|
||||
|
||||
@@ -408,7 +408,7 @@ Checking Shipments::
|
||||
>>> mix_return.click('done')
|
||||
>>> move_return, = mix_return.moves
|
||||
>>> move_return.product.rec_name
|
||||
u'product'
|
||||
'product'
|
||||
>>> move_return.quantity
|
||||
2.0
|
||||
|
||||
@@ -417,7 +417,7 @@ Checking the invoice::
|
||||
>>> mix.reload()
|
||||
>>> mix_invoice, = mix.invoices
|
||||
>>> mix_invoice.type
|
||||
u'in'
|
||||
'in'
|
||||
>>> len(mix_invoice.lines)
|
||||
3
|
||||
>>> sorted(l.quantity for l in mix_invoice.lines if l.quantity)
|
||||
@@ -447,11 +447,11 @@ Mixing stuff with an invoice method 'on shipment'::
|
||||
>>> mix.click('confirm')
|
||||
>>> mix.click('process')
|
||||
>>> mix.state
|
||||
u'processing'
|
||||
'processing'
|
||||
>>> mix.shipment_state
|
||||
u'waiting'
|
||||
'waiting'
|
||||
>>> mix.invoice_state
|
||||
u'none'
|
||||
'none'
|
||||
>>> len(mix.moves), len(mix.shipment_returns), len(mix.invoices)
|
||||
(2, 1, 0)
|
||||
|
||||
@@ -477,7 +477,7 @@ Checking Shipments::
|
||||
>>> mix_return.click('done')
|
||||
>>> move_return, = mix_return.moves
|
||||
>>> move_return.product.rec_name
|
||||
u'product'
|
||||
'product'
|
||||
>>> move_return.quantity
|
||||
3.0
|
||||
|
||||
@@ -494,11 +494,11 @@ Purchase services::
|
||||
>>> service_purchase.click('confirm')
|
||||
>>> service_purchase.click('process')
|
||||
>>> service_purchase.state
|
||||
u'processing'
|
||||
'processing'
|
||||
>>> service_purchase.shipment_state
|
||||
u'none'
|
||||
'none'
|
||||
>>> service_purchase.invoice_state
|
||||
u'waiting'
|
||||
'waiting'
|
||||
>>> service_invoice, = service_purchase.invoices
|
||||
|
||||
Pay the service invoice::
|
||||
@@ -511,17 +511,17 @@ Pay the service invoice::
|
||||
>>> pay.execute('choice')
|
||||
>>> service_invoice.reload()
|
||||
>>> service_invoice.state
|
||||
u'paid'
|
||||
'paid'
|
||||
|
||||
Check service purchase states::
|
||||
|
||||
>>> service_purchase.reload()
|
||||
>>> service_purchase.invoice_state
|
||||
u'paid'
|
||||
'paid'
|
||||
>>> service_purchase.shipment_state
|
||||
u'none'
|
||||
'none'
|
||||
>>> service_purchase.state
|
||||
u'done'
|
||||
'done'
|
||||
|
||||
Create a purchase to be invoiced on shipment partially and check correctly
|
||||
linked to invoices::
|
||||
@@ -556,7 +556,7 @@ linked to invoices::
|
||||
>>> stock_move.quantity
|
||||
5.0
|
||||
>>> stock_move.state
|
||||
u'done'
|
||||
'done'
|
||||
|
||||
Create a purchase to be invoiced on order, partially send it and check
|
||||
correctly linked to invoices::
|
||||
@@ -592,11 +592,11 @@ correctly linked to invoices::
|
||||
>>> draft_stock_move.quantity
|
||||
2.0
|
||||
>>> draft_stock_move.state
|
||||
u'draft'
|
||||
'draft'
|
||||
>>> stock_move.quantity
|
||||
8.0
|
||||
>>> stock_move.state
|
||||
u'done'
|
||||
'done'
|
||||
|
||||
Deleting a line from a invoice should recreate it::
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ Create empty purchase::
|
||||
>>> purchase.party = supplier
|
||||
>>> purchase.click('quote')
|
||||
>>> purchase.state
|
||||
u'quotation'
|
||||
'quotation'
|
||||
>>> purchase.untaxed_amount
|
||||
Decimal('0')
|
||||
>>> purchase.tax_amount
|
||||
@@ -46,17 +46,17 @@ Create empty purchase::
|
||||
Decimal('0')
|
||||
>>> purchase.click('confirm')
|
||||
>>> purchase.state
|
||||
u'confirmed'
|
||||
'confirmed'
|
||||
>>> purchase.click('process')
|
||||
>>> purchase.state
|
||||
u'done'
|
||||
'done'
|
||||
>>> purchase.shipment_state
|
||||
u'none'
|
||||
'none'
|
||||
>>> len(purchase.moves)
|
||||
0
|
||||
>>> len(purchase.shipment_returns)
|
||||
0
|
||||
>>> purchase.invoice_state
|
||||
u'none'
|
||||
'none'
|
||||
>>> len(purchase.invoices)
|
||||
0
|
||||
|
||||
@@ -92,6 +92,6 @@ Change the party::
|
||||
>>> modify_header.execute('modify')
|
||||
|
||||
>>> purchase.party.name
|
||||
u'Another Supplier'
|
||||
'Another Supplier'
|
||||
>>> purchase.untaxed_amount, purchase.tax_amount, purchase.total_amount
|
||||
(Decimal('15.00'), Decimal('0'), Decimal('15.00'))
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
[tox]
|
||||
envlist = {py27,py34,py35,py36}-{sqlite,postgresql},pypy-{sqlite,postgresql}
|
||||
envlist = {py34,py35,py36}-{sqlite,postgresql},pypy3-{sqlite,postgresql}
|
||||
|
||||
[testenv]
|
||||
commands = {envpython} setup.py test
|
||||
deps =
|
||||
{py27,py34,py35,py36}-postgresql: psycopg2 >= 2.5
|
||||
pypy-postgresql: psycopg2cffi >= 2.5
|
||||
{py34,py35,py36}-postgresql: psycopg2 >= 2.5
|
||||
pypy3-postgresql: psycopg2cffi >= 2.5
|
||||
sqlite: sqlitebck
|
||||
setenv =
|
||||
sqlite: TRYTOND_DATABASE_URI={env:SQLITE_URI:sqlite://}
|
||||
|
||||
Reference in New Issue
Block a user