first commit
This commit is contained in:
668
modules/web_shop_vue_storefront/web.py
Normal file
668
modules/web_shop_vue_storefront/web.py
Normal file
@@ -0,0 +1,668 @@
|
||||
# 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 functools import wraps
|
||||
|
||||
import elasticsearch
|
||||
from elasticsearch import VERSION as ES_VERSION
|
||||
from elasticsearch import Elasticsearch
|
||||
|
||||
from trytond.exceptions import RateLimitException
|
||||
from trytond.i18n import gettext, lazy_gettext
|
||||
from trytond.model import ModelSQL, Unique, fields
|
||||
from trytond.pool import Pool, PoolMeta
|
||||
from trytond.pyson import Eval
|
||||
|
||||
from .exceptions import BadRequest, LoginException, NotFound
|
||||
|
||||
|
||||
def migrate_doc_type(func):
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
if ES_VERSION >= (7,):
|
||||
kwargs = kwargs.copy()
|
||||
doc_type = kwargs.pop('doc_type')
|
||||
kwargs['index'] += '_' + doc_type
|
||||
return func(*args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
|
||||
class VSFElasticsearch(Elasticsearch):
|
||||
|
||||
@migrate_doc_type
|
||||
def index(self, **kwargs):
|
||||
return super().index(**kwargs)
|
||||
|
||||
@migrate_doc_type
|
||||
def delete(self, **kwargs):
|
||||
return super().delete(**kwargs)
|
||||
|
||||
|
||||
def join_name(firstname, lastname):
|
||||
# Use unbreakable spaces in firstname
|
||||
# to prevent to split on them
|
||||
firstname = firstname.replace(' ', ' ')
|
||||
return ' '.join([firstname, lastname])
|
||||
|
||||
|
||||
def split_name(name):
|
||||
return (name.split(' ', 1) + [''])[:2]
|
||||
|
||||
|
||||
def issubdict(dct, other):
|
||||
for key, value in dct.items():
|
||||
if value != other.get(key):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def with_user(required=False):
|
||||
def decorator(func):
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
pool = Pool()
|
||||
User = pool.get('web.user')
|
||||
token = kwargs.pop('token', None)
|
||||
if token:
|
||||
user = User.get_user(token)
|
||||
else:
|
||||
user = kwargs.get('user')
|
||||
if required and not user:
|
||||
raise LoginException()
|
||||
kwargs['user'] = user
|
||||
return func(*args, **kwargs)
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
|
||||
class Shop(metaclass=PoolMeta):
|
||||
__name__ = 'web.shop'
|
||||
|
||||
vsf_elasticsearch_url = fields.Char(
|
||||
"Elasticsearch URL",
|
||||
states={
|
||||
'required': Eval('type') == 'vsf',
|
||||
'invisible': Eval('type') != 'vsf',
|
||||
})
|
||||
vsf_elasticsearch_index = fields.Char(
|
||||
"Elasticsearch Index",
|
||||
states={
|
||||
'required': Eval('type') == 'vsf',
|
||||
'invisible': Eval('type') != 'vsf',
|
||||
})
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
cls.type.selection.append(('vsf', "Vue Storefront"))
|
||||
|
||||
@classmethod
|
||||
def default_vsf_elasticsearch_url(cls):
|
||||
return 'http://localhost:9200/'
|
||||
|
||||
@classmethod
|
||||
def default_vsf_elasticsearch_index(cls):
|
||||
return 'vue_storefront_catalog'
|
||||
|
||||
@classmethod
|
||||
def view_attributes(cls):
|
||||
return super().view_attributes() + [
|
||||
('//page[@id="vsf"]', 'states', {
|
||||
'invisible': Eval('type') != 'vsf',
|
||||
}),
|
||||
]
|
||||
|
||||
@property
|
||||
def to_sync(self):
|
||||
result = super().to_sync
|
||||
if self.type == 'vsf':
|
||||
result = True
|
||||
return result
|
||||
|
||||
def get_vsf_elasticsearch(self):
|
||||
return VSFElasticsearch(self.vsf_elasticsearch_url)
|
||||
|
||||
@classmethod
|
||||
def vsf_update(cls, shops=None):
|
||||
pool = Pool()
|
||||
Product = pool.get('product.product')
|
||||
ProductTemplate = pool.get('product.template')
|
||||
Category = pool.get('product.category')
|
||||
try:
|
||||
ProductAttribute = pool.get('product.attribute')
|
||||
except KeyError:
|
||||
ProductAttribute = None
|
||||
if shops is None:
|
||||
shops = cls.search([
|
||||
('type', '=', 'vsf'),
|
||||
])
|
||||
cls.lock(shops)
|
||||
for shop in shops:
|
||||
es = shop.get_vsf_elasticsearch()
|
||||
if ProductAttribute:
|
||||
attributes = shop.get_attributes()
|
||||
ProductAttribute.set_vsf_identifier(attributes)
|
||||
categories = shop.get_categories()
|
||||
Category.set_vsf_identifier(categories)
|
||||
products, prices, taxes = shop.get_products()
|
||||
Product.set_vsf_identifier(products)
|
||||
|
||||
templates = set()
|
||||
for product in products:
|
||||
if product.vsf_is_configurable(shop):
|
||||
templates.add(product.template)
|
||||
continue
|
||||
entity = product.get_vsf_entity(
|
||||
shop, price=prices[product.id], tax=taxes[product.id])
|
||||
es.index(
|
||||
index=shop.vsf_elasticsearch_index,
|
||||
doc_type='product',
|
||||
id=product.vsf_identifier.id,
|
||||
body=entity)
|
||||
templates = ProductTemplate.browse(templates)
|
||||
ProductTemplate.set_vsf_identifier(templates)
|
||||
for template in templates:
|
||||
template_products = template.get_vsf_products(shop)
|
||||
price, tax = min(
|
||||
(prices[p.id], taxes[p.id]) for p in template_products
|
||||
if prices[p.id] is not None and taxes[p.id] is not None)
|
||||
entity = template.get_vsf_entity(shop, price=price, tax=tax)
|
||||
entity['configurable_children'] = [
|
||||
product.get_vsf_entity(
|
||||
shop, price=prices[product.id], tax=taxes[product.id])
|
||||
for product in template_products]
|
||||
es.index(
|
||||
index=shop.vsf_elasticsearch_index,
|
||||
doc_type='product',
|
||||
id=template.vsf_identifier.id,
|
||||
body=entity)
|
||||
|
||||
for category in categories:
|
||||
entity = category.get_vsf_entity(shop)
|
||||
es.index(
|
||||
index=shop.vsf_elasticsearch_index,
|
||||
doc_type='category',
|
||||
id=category.vsf_identifier.id,
|
||||
body=entity)
|
||||
|
||||
if ProductAttribute:
|
||||
for attribute in attributes:
|
||||
entity = attribute.get_vsf_entity(shop)
|
||||
es.index(
|
||||
index=shop.vsf_elasticsearch_index,
|
||||
doc_type='attribute',
|
||||
id=attribute.vsf_identifier.id,
|
||||
body=entity)
|
||||
|
||||
for product in shop.products_removed:
|
||||
template = product.template
|
||||
if template.vsf_identifier:
|
||||
template_products = product.template.get_vsf_products(shop)
|
||||
if not template_products:
|
||||
try:
|
||||
es.delete(
|
||||
index=shop.vsf_elasticsearch_index,
|
||||
doc_type='product',
|
||||
id=template.vsf_identifier.id)
|
||||
except elasticsearch.exceptions.NotFoundError:
|
||||
pass
|
||||
if product.vsf_identifier:
|
||||
try:
|
||||
es.delete(
|
||||
index=shop.vsf_elasticsearch_index,
|
||||
doc_type='product',
|
||||
id=product.vsf_identifier.id)
|
||||
except elasticsearch.exceptions.NotFoundError:
|
||||
pass
|
||||
shop.products_removed = []
|
||||
|
||||
for category in shop.categories_removed:
|
||||
if category.vsf_identifier:
|
||||
try:
|
||||
es.delete(
|
||||
index=shop.vsf_elasticsearch_index,
|
||||
doc_type='category',
|
||||
id=category.vsf_identifier.id)
|
||||
except elasticsearch.exceptions.NotFoundError:
|
||||
pass
|
||||
shop.categories_removed = []
|
||||
|
||||
if ProductAttribute:
|
||||
for attribute in shop.attributes_removed:
|
||||
if attribute.vsf_identifier:
|
||||
try:
|
||||
es.delete(
|
||||
index=shop.vsf_elasticsearch_index,
|
||||
doc_type='attribute',
|
||||
id=attribute.vsf_identifier.id)
|
||||
except elasticsearch.exceptions.NotFoundError:
|
||||
pass
|
||||
shop.attributes_removed = []
|
||||
|
||||
cls.save(shops)
|
||||
|
||||
def POST_vsf_user_create(self, data):
|
||||
pool = Pool()
|
||||
User = pool.get('web.user')
|
||||
Party = pool.get('party.party')
|
||||
firstname = data['customer']['firstname']
|
||||
lastname = data['customer']['lastname']
|
||||
email = data['customer']['email']
|
||||
user = User(email=email, password=data['password'])
|
||||
party = Party(name=join_name(firstname, lastname))
|
||||
party.save()
|
||||
user.party = party
|
||||
user.save()
|
||||
firstname, lastname = split_name(user.party.name)
|
||||
return {
|
||||
'email': user.email,
|
||||
'firstname': firstname,
|
||||
'lastname': lastname,
|
||||
'addresses': [],
|
||||
}
|
||||
|
||||
def POST_vsf_user_login(self, data):
|
||||
pool = Pool()
|
||||
User = pool.get('web.user')
|
||||
try:
|
||||
user = User.authenticate(data['username'], data['password'])
|
||||
except RateLimitException:
|
||||
raise LoginException(gettext(
|
||||
'web_shop_vue_storefront.msg_login_wrong'))
|
||||
if user:
|
||||
return user.new_session()
|
||||
else:
|
||||
raise LoginException(gettext(
|
||||
'web_shop_vue_storefront.msg_login_wrong'))
|
||||
|
||||
def POST_vsf_user_reset_password(self, data):
|
||||
pool = Pool()
|
||||
User = pool.get('web.user')
|
||||
users = User.search([
|
||||
('email', '=', data['email']),
|
||||
])
|
||||
User.reset_password(users)
|
||||
|
||||
@with_user(required=True)
|
||||
def POST_vsf_user_change_password(self, data, user):
|
||||
pool = Pool()
|
||||
User = pool.get('web.user')
|
||||
try:
|
||||
user = User.authenticate(user.email, data['currentPassword'])
|
||||
except RateLimitException:
|
||||
raise LoginException(gettext(
|
||||
'web_shop_vue_storefront.msg_login_wrong'))
|
||||
if user:
|
||||
user.password = data['newPassword']
|
||||
user.save()
|
||||
else:
|
||||
raise LoginException(gettext(
|
||||
'web_shop_vue_storefront.msg_login_wrong'))
|
||||
|
||||
@with_user(required=True)
|
||||
def GET_vsf_user_order_history(
|
||||
self, data, user, pageSize='20', currentPage='1'):
|
||||
pool = Pool()
|
||||
Sale = pool.get('sale.sale')
|
||||
try:
|
||||
pageSize = int(pageSize)
|
||||
currentPage = int(currentPage)
|
||||
except ValueError:
|
||||
raise BadRequest()
|
||||
sales = Sale.search([
|
||||
('party', '=', user.party),
|
||||
('state', 'in', ['confirmed', 'processing', 'done']),
|
||||
],
|
||||
offset=pageSize * (currentPage - 1),
|
||||
limit=pageSize,
|
||||
order=[
|
||||
('sale_date', 'DESC'),
|
||||
('id', 'DESC'),
|
||||
])
|
||||
items = []
|
||||
for sale in sales:
|
||||
items.append(sale.get_vsf_user_order_history())
|
||||
return {'items': items}
|
||||
|
||||
@with_user(required=True)
|
||||
def GET_vsf_user_me(self, data, user):
|
||||
return user.get_vsf()
|
||||
|
||||
@with_user(required=True)
|
||||
def POST_vsf_user_me(self, data, user):
|
||||
user.set_vsf(data['customer'])
|
||||
user.save()
|
||||
return user.get_vsf()
|
||||
|
||||
def GET_vsf_stock_check(self, data, sku):
|
||||
try:
|
||||
return self.GET_vsf_stock_list(data, sku)[0]
|
||||
except IndexError:
|
||||
raise NotFound()
|
||||
|
||||
def GET_vsf_stock_list(self, data, skus):
|
||||
pool = Pool()
|
||||
Product = pool.get('product.product')
|
||||
Template = pool.get('product.template')
|
||||
skus = skus.split(',')
|
||||
products = Product.search([
|
||||
('vsf_sku', 'in', skus),
|
||||
('web_shops', '=', self.id),
|
||||
])
|
||||
products += Template.search([
|
||||
('vsf_sku', 'in', skus),
|
||||
('products.web_shops', '=', self.id),
|
||||
])
|
||||
return [p.get_vsf_stock() for p in products]
|
||||
|
||||
@with_user()
|
||||
def POST_vsf_cart_create(self, data, user=None):
|
||||
party = user.party if user else None
|
||||
sale = self.get_sale(party)
|
||||
sale.save()
|
||||
return sale.vsf_id
|
||||
|
||||
@with_user()
|
||||
def GET_vsf_cart_pull(self, data, cartId, user=None):
|
||||
pool = Pool()
|
||||
Sale = pool.get('sale.sale')
|
||||
sale = Sale.search_vsf(cartId, self, user)
|
||||
return [line.get_vsf() for line in sale.lines if line.product]
|
||||
|
||||
@with_user()
|
||||
def POST_vsf_cart_update(self, data, cartId, user=None):
|
||||
pool = Pool()
|
||||
Sale = pool.get('sale.sale')
|
||||
SaleLine = pool.get('sale.line')
|
||||
sale = Sale.search_vsf(cartId, self, user)
|
||||
if data['cartItem'].get('item_id'):
|
||||
line = SaleLine(data['cartItem']['item_id'])
|
||||
if line.sale != sale:
|
||||
raise BadRequest()
|
||||
else:
|
||||
line = SaleLine(sale=sale)
|
||||
line.set_vsf(data['cartItem'])
|
||||
line.save()
|
||||
return line.get_vsf()
|
||||
|
||||
@with_user()
|
||||
def POST_vsf_cart_delete(self, data, cartId, user=None):
|
||||
pool = Pool()
|
||||
Sale = pool.get('sale.sale')
|
||||
SaleLine = pool.get('sale.line')
|
||||
sale = Sale.search_vsf(cartId, self, user)
|
||||
line = SaleLine(data['cartItem']['item_id'])
|
||||
if line.sale != sale:
|
||||
raise BadRequest()
|
||||
SaleLine.delete([line])
|
||||
return True
|
||||
|
||||
@with_user()
|
||||
def GET_vsf_cart_totals(self, data, cartId, user=None):
|
||||
pool = Pool()
|
||||
Sale = pool.get('sale.sale')
|
||||
sale = Sale.search_vsf(cartId, self, user)
|
||||
return sale.get_vsf()
|
||||
|
||||
@with_user()
|
||||
def GET_vsf_cart_payment_methods(self, data, cartId, user=None):
|
||||
return []
|
||||
|
||||
@with_user()
|
||||
def POST_vsf_cart_shipping_methods(self, data, cartId, user=None):
|
||||
return []
|
||||
|
||||
@with_user()
|
||||
def POST_vsf_cart_shipping_information(self, data, cartId, user=None):
|
||||
pool = Pool()
|
||||
Sale = pool.get('sale.sale')
|
||||
sale = Sale.search_vsf(cartId, self, user)
|
||||
return sale.get_vsf()
|
||||
|
||||
@with_user(required=True)
|
||||
def POST_vsf_order_create(self, data, cartId, user):
|
||||
pool = Pool()
|
||||
Sale = pool.get('sale.sale')
|
||||
sale = Sale.search_vsf(cartId, self, user)
|
||||
self.vsf_order_create(data, sale, user)
|
||||
return 'OK'
|
||||
|
||||
def vsf_order_create(self, data, sale, user):
|
||||
pool = Pool()
|
||||
Sale = pool.get('sale.sale')
|
||||
SaleLine = pool.get('sale.line')
|
||||
sale.set_vsf(data, user)
|
||||
sku2lines = {
|
||||
line.product.vsf_sku: line for line in sale.lines if line.product}
|
||||
for product in data.get('products', []):
|
||||
sku = product['sku']
|
||||
line = sku2lines.get(sku)
|
||||
if not line:
|
||||
line = SaleLine(sale=sale)
|
||||
sku2lines[sku] = line
|
||||
line.set_vsf(product)
|
||||
sale.lines = sku2lines.values()
|
||||
sale.save()
|
||||
Sale.quote([sale])
|
||||
payment_method = data['addressInformation']['payment_method_code']
|
||||
if payment_method == 'cashondelivery':
|
||||
Sale.confirm([sale])
|
||||
return sale
|
||||
|
||||
|
||||
class ShopCoupon(metaclass=PoolMeta):
|
||||
__name__ = 'web.shop'
|
||||
|
||||
@with_user()
|
||||
def POST_vsf_cart_apply_coupon(self, data, cartId, coupon, user=None):
|
||||
pool = Pool()
|
||||
Sale = pool.get('sale.sale')
|
||||
sale = Sale.search_vsf(cartId, self, user)
|
||||
PromotionCouponNumber = pool.get('sale.promotion.coupon.number')
|
||||
try:
|
||||
coupon, = PromotionCouponNumber.search([
|
||||
('number', 'ilike', coupon),
|
||||
], limit=1)
|
||||
except ValueError:
|
||||
return False
|
||||
sale.coupons = [coupon]
|
||||
sale.save()
|
||||
return True
|
||||
|
||||
@with_user()
|
||||
def POST_vsf_cart_delete_coupon(self, data, cartId, user=None):
|
||||
pool = Pool()
|
||||
Sale = pool.get('sale.sale')
|
||||
sale = Sale.search_vsf(cartId, self, user)
|
||||
sale.coupons = []
|
||||
sale.save()
|
||||
return True
|
||||
|
||||
@with_user()
|
||||
def POST_vsf_cart_coupon(self, data, cartId, user=None):
|
||||
pool = Pool()
|
||||
Sale = pool.get('sale.sale')
|
||||
sale = Sale.search_vsf(cartId, self, user)
|
||||
if sale.coupons:
|
||||
return sale.coupons[0].number
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
class ShopShipmentCost(metaclass=PoolMeta):
|
||||
__name__ = 'web.shop'
|
||||
|
||||
@with_user()
|
||||
def POST_vsf_cart_shipping_methods(self, data, cartId, user=None):
|
||||
pool = Pool()
|
||||
Sale = pool.get('sale.sale')
|
||||
methods = super().POST_vsf_cart_shipping_methods(
|
||||
data, cartId, user=user)
|
||||
sale = Sale.search_vsf(cartId, self, user)
|
||||
sale.set_vsf_shipping_methods(data)
|
||||
for carrier in sale.available_carriers:
|
||||
method = carrier.get_vsf()
|
||||
sale.carrier = carrier
|
||||
method['price_incl_tax'] = sale.compute_shipment_cost(carrier)
|
||||
methods.append(method)
|
||||
return methods
|
||||
|
||||
@with_user()
|
||||
def POST_vsf_cart_shipping_information(self, data, cartId, user=None):
|
||||
pool = Pool()
|
||||
Sale = pool.get('sale.sale')
|
||||
sale = Sale.search_vsf(cartId, self, user)
|
||||
sale.set_vsf(data, user)
|
||||
sale.save()
|
||||
return super().POST_vsf_cart_shipping_information(
|
||||
data, cartId, user=user)
|
||||
|
||||
|
||||
class ShopVSFIdentifier(ModelSQL):
|
||||
__name__ = 'web.shop.vsf_identifier'
|
||||
|
||||
record = fields.Reference("Record", 'get_records', required=True)
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
t = cls.__table__()
|
||||
cls._sql_constraints = [
|
||||
('record_unique', Unique(t, t.record),
|
||||
'web_shop_vue_storefront.msg_identifier_record_unique'),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def get_records(cls):
|
||||
pool = Pool()
|
||||
Model = pool.get('ir.model')
|
||||
get_name = Model.get_name
|
||||
models = (klass.__name__ for _, klass in pool.iterobject()
|
||||
if issubclass(klass, ShopVSFIdentifierMixin))
|
||||
return [(m, get_name(m)) for m in models]
|
||||
|
||||
|
||||
class ShopVSFIdentifierMixin:
|
||||
__slots__ = ()
|
||||
vsf_identifier = fields.Many2One(
|
||||
'web.shop.vsf_identifier',
|
||||
lazy_gettext('web_shop_vue_storefront.msg_vsf_identifier'),
|
||||
ondelete='RESTRICT', readonly=True)
|
||||
|
||||
@classmethod
|
||||
def set_vsf_identifier(cls, records):
|
||||
pool = Pool()
|
||||
Identifier = pool.get('web.shop.vsf_identifier')
|
||||
vsf_identifiers = []
|
||||
for record in records:
|
||||
if not record.vsf_identifier:
|
||||
record.vsf_identifier = Identifier(record=record)
|
||||
vsf_identifiers.append(record.vsf_identifier)
|
||||
Identifier.save(vsf_identifiers)
|
||||
cls.save(records)
|
||||
|
||||
|
||||
class User(metaclass=PoolMeta):
|
||||
__name__ = 'web.user'
|
||||
|
||||
def get_vsf(self):
|
||||
if not self.party:
|
||||
return {
|
||||
'email': self.email,
|
||||
}
|
||||
firstname, lastname = split_name(self.party.name)
|
||||
data = {
|
||||
'email': self.email,
|
||||
'firstname': firstname,
|
||||
'lastname': lastname,
|
||||
'addresses': (
|
||||
[a.get_vsf() for a in self.party.addresses]
|
||||
+ [a.get_vsf(self.party) for p in self.secondary_parties
|
||||
for a in p.addresses if p != self.party]),
|
||||
}
|
||||
|
||||
default_billing = self.invoice_address
|
||||
if not default_billing:
|
||||
default_billing = self.party.address_get('invoice')
|
||||
if default_billing:
|
||||
data['default_billing'] = default_billing.id
|
||||
|
||||
default_shipping = self.shipment_address
|
||||
if not default_shipping:
|
||||
default_shipping = self.party.address_get('delivery')
|
||||
if default_shipping:
|
||||
data['default_shipping'] = default_shipping.id
|
||||
|
||||
return data
|
||||
|
||||
def set_vsf(self, data):
|
||||
pool = Pool()
|
||||
Party = pool.get('party.party')
|
||||
Address = pool.get('party.address')
|
||||
self.email = data['email']
|
||||
if not self.party:
|
||||
self.party = Party()
|
||||
self.party.name = join_name(data['firstname'], data['lastname'])
|
||||
|
||||
default_billing = None
|
||||
default_shipping = None
|
||||
addresses = []
|
||||
for address_data in data['addresses']:
|
||||
address = self.set_vsf_address(address_data, self.party)
|
||||
addresses.append(address)
|
||||
if ((address.id and address.id == data.get('default_billing'))
|
||||
or address_data.get('default_billing')):
|
||||
default_billing = address
|
||||
if ((address.id and address.id == data.get('default_shipping'))
|
||||
or address_data.get('default_shipping')):
|
||||
default_shipping = address
|
||||
|
||||
if address_data.get('id'):
|
||||
if address_data['id'] != address.id:
|
||||
address = Address(address_data['id'])
|
||||
if (address.party != self.party
|
||||
and address.party not in self.secondary_parties):
|
||||
raise BadRequest()
|
||||
address.active = False
|
||||
addresses.append(address)
|
||||
Address.save(addresses)
|
||||
self.invoice_address = default_billing
|
||||
self.shipment_address = default_shipping
|
||||
|
||||
def set_vsf_address(self, address_data, party):
|
||||
pool = Pool()
|
||||
Party = pool.get('party.party')
|
||||
Address = pool.get('party.address')
|
||||
Identifier = pool.get('party.identifier')
|
||||
|
||||
addresses = self.party.addresses
|
||||
for party in self.secondary_parties:
|
||||
addresses += party.addresses
|
||||
|
||||
for address in addresses:
|
||||
if issubdict(address.get_vsf(party), address_data):
|
||||
return address
|
||||
|
||||
address = Address()
|
||||
party = address.party = self.party
|
||||
if address_data.get('company'):
|
||||
for company_party in self.secondary_parties:
|
||||
tax_code = (
|
||||
company_party.tax_identifier.code
|
||||
if company_party.tax_identifier else '')
|
||||
if (company_party.name == address_data['company']
|
||||
and (not address_data.get('vat_id')
|
||||
or tax_code == address_data['vat_id'])):
|
||||
break
|
||||
else:
|
||||
identifier = Identifier()
|
||||
identifier.set_vsf_tax_identifier(
|
||||
address_data['vat_id'])
|
||||
company_party = Party(
|
||||
name=address_data['company'],
|
||||
identifiers=[identifier])
|
||||
company_party.save()
|
||||
self.secondary_parties += (company_party,)
|
||||
self.save()
|
||||
address.party = company_party
|
||||
address.set_vsf(address_data, party)
|
||||
return address
|
||||
Reference in New Issue
Block a user