first commit

This commit is contained in:
root
2026-03-14 09:42:12 +00:00
commit 0adbd20c2c
10991 changed files with 1646955 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.

View File

@@ -0,0 +1,278 @@
================================
Web Shop Vue Storefront Scenario
================================
Imports::
>>> import base64
>>> from decimal import Decimal
>>> from unittest.mock import ANY, MagicMock, patch
>>> from proteus import Model
>>> from trytond.modules.account.tests.tools import create_chart, get_accounts
>>> from trytond.modules.company.tests.tools import create_company
>>> from trytond.modules.web_shop_vue_storefront import web
>>> from trytond.modules.web_shop_vue_storefront.tests.tools import AnyDictWith
>>> from trytond.tests.tools import activate_modules
>>> pixel = base64.decodebytes(
... b'/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8S'
... b'EhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/wAALCAABAAEBAREA/8QAHwAA'
... b'AQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQR'
... b'BRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RF'
... b'RkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ip'
... b'qrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEB'
... b'AAA/APsuv//Z')
Patch elasticsearch::
>>> es = MagicMock()
>>> _ = patch.object(
... web, 'VSFElasticsearch', return_value=es).start()
Install web_shop_vue_storefront::
>>> config = activate_modules(
... ['web_shop_vue_storefront', 'product_attribute', 'product_image'],
... create_company, create_chart)
Get accounts::
>>> accounts = get_accounts()
Define a web shop::
>>> WebShop = Model.get('web.shop')
>>> web_shop = WebShop(name="Web Shop")
>>> web_shop.type = 'vsf'
>>> web_shop.save()
Create categories::
>>> Category = Model.get('product.category')
>>> category1 = Category(name="Category 1")
>>> category1.save()
>>> sub_category = Category(name="Sub Category", parent=category1)
>>> sub_category.save()
>>> category2 = Category(name="Category 2")
>>> category2.save()
>>> account_category = Category(name="Account Category")
>>> account_category.accounting = True
>>> account_category.account_expense = accounts['expense']
>>> account_category.account_revenue = accounts['revenue']
>>> account_category.save()
Create attribute set::
>>> ProductAttributeSet = Model.get('product.attribute.set')
>>> ProductAttribute = Model.get('product.attribute')
>>> attribute_set = ProductAttributeSet(name="Attributes")
>>> attribute = attribute_set.attributes.new()
>>> attribute.name = 'attr1'
>>> attribute.string = "Attribute 1"
>>> attribute.type_ = 'selection'
>>> attribute.selection = "opt1:Option1\nopt2:Option2"
>>> attribute = attribute_set.attributes.new()
>>> attribute.name = 'attr2'
>>> attribute.string = "Attribute 1"
>>> attribute.type_ = 'boolean'
>>> attribute_set.save()
>>> attribute1, attribute2 = attribute_set.attributes
Create products::
>>> ProductUom = Model.get('product.uom')
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
>>> ProductTemplate = Model.get('product.template')
>>> Product = Model.get('product.product')
>>> template = ProductTemplate()
>>> template.name = "Product 1"
>>> template.default_uom = unit
>>> template.type = 'goods'
>>> template.salable = True
>>> template.list_price = Decimal(10)
>>> template.account_category = account_category
>>> template.categories.append(Category(category1.id))
>>> template.categories.append(Category(sub_category.id))
>>> template.save()
>>> product1, = template.products
>>> product1.suffix_code = 'PROD1'
>>> image = product1.images.new()
>>> image.template = template
>>> image.image = pixel
>>> product1.save()
>>> template = ProductTemplate()
>>> template.name = "Product 2"
>>> template.default_uom = unit
>>> template.type = 'goods'
>>> template.salable = True
>>> template.list_price = Decimal(20)
>>> template.account_category = account_category
>>> template.save()
>>> product2, = template.products
>>> product2.suffix_code = 'PROD2'
>>> product2.save()
>>> configurable = ProductTemplate()
>>> configurable.name = "Configurable"
>>> configurable.code = "CONF"
>>> configurable.default_uom = unit
>>> configurable.type = 'goods'
>>> configurable.salable = True
>>> configurable.list_price = Decimal(50)
>>> configurable.attribute_set = attribute_set
>>> configurable.account_category = account_category
>>> image = configurable.images.new()
>>> image.image = pixel
>>> configurable1, = configurable.products
>>> configurable1.suffix_code = "1"
>>> configurable1.attributes = {
... 'attr1': 'opt1',
... 'attr2': True,
... }
>>> configurable2 = configurable.products.new()
>>> configurable2.suffix_code = "2"
>>> configurable2.attributes = {
... 'attr1': 'opt2',
... 'attr2': True,
... }
>>> configurable.save()
>>> configurable1, configurable2 = configurable.products
Set categories, products and attributes to web shop::
>>> web_shop.categories.extend([
... Category(category1.id),
... Category(sub_category.id),
... Category(category2.id)])
>>> web_shop.products.extend([
... Product(product1.id),
... Product(product2.id),
... Product(configurable1.id),
... Product(configurable2.id)])
>>> web_shop.attributes.extend([
... ProductAttribute(attribute1.id),
... ProductAttribute(attribute2.id)])
>>> web_shop.save()
Run VSF update::
>>> es.reset_mock()
>>> Cron = Model.get('ir.cron')
>>> cron_sync, = Cron.find([
... ('method', '=', 'web.shop|vsf_update'),
... ])
>>> cron_sync.click('run_once')
>>> es.index.call_count
8
>>> es.index.assert_any_call(
... id=category1.vsf_identifier.id, index='vue_storefront_catalog',
... doc_type='category', body=AnyDictWith({
... 'name': "Category 1",
... 'parent_id': None,
... 'url_key': 'category-1',
... 'url_path': 'category-1',
... 'level': 1,
... 'product_count': 1,
... 'children_data': [AnyDictWith({})],
... }))
>>> es.index.assert_any_call(
... id=sub_category.vsf_identifier.id, index='vue_storefront_catalog',
... doc_type='category', body=AnyDictWith({
... 'name': "Sub Category",
... 'parent_id': category1.vsf_identifier.id,
... 'url_key': 'sub-category',
... 'url_path': 'category-1/sub-category',
... 'level': 2,
... 'product_count': 1,
... 'children_data': [],
... }))
>>> es.index.assert_any_call(
... id=product1.vsf_identifier.id, index='vue_storefront_catalog',
... doc_type='product', body=AnyDictWith({
... 'name': "Product 1",
... 'image': ANY,
... 'sku': 'PROD1',
... 'url_key': 'product-1',
... 'type_id': 'simple',
... 'price': 10,
... 'price_tax': 0,
... 'price_incl_tax': 10,
... 'status': 3,
... 'category_ids': [ANY, ANY],
... 'category': [AnyDictWith({}), AnyDictWith({})],
... 'stock': [{
... 'is_in_stock': False,
... 'qty': 0,
... }],
... }))
>>> es.index.assert_any_call(
... id=configurable.vsf_identifier.id, index='vue_storefront_catalog',
... doc_type='product', body=AnyDictWith({
... 'name': "Configurable",
... 'image': ANY,
... 'sku': 'CONF',
... 'url_key': 'configurable',
... 'type_id': 'configurable',
... 'price': 50,
... 'price_tax': 0,
... 'price_incl_tax': 50,
... 'status': 3,
... 'category_ids': [],
... 'category': [],
... 'stock': [{
... 'is_in_stock': False,
... 'qty': 0,
... }],
... 'attr1_options': [1, 2],
... 'attr2_options': [],
... 'configurable_options': [
... AnyDictWith({
... 'attribute_code': 'attr1',
... 'label': "Attribute 1",
... 'product_id': configurable.vsf_identifier.id,
... 'values': [
... {'value_index': 1, 'label': "Option1"},
... {'value_index': 2, 'label': "Option2"},
... ],
... }),
... AnyDictWith({}),
... ],
... 'configurable_children': [
... AnyDictWith({'sku': 'CONF1'}),
... AnyDictWith({'sku': 'CONF2'}),
... ],
... }))
>>> es.index.assert_any_call(
... id=attribute1.vsf_identifier.id, index='vue_storefront_catalog',
... doc_type='attribute', body=AnyDictWith({
... 'attribute_code': 'attr1',
... 'frontend_input': 'selection',
... 'frontend_label': "Attribute 1",
... 'options': [
... {'value': 1, 'name': 'opt1', 'label': "Option1"},
... {'value': 2, 'name': 'opt2', 'label': "Option2"},
... ],
... }))
Remove a category, a product and an attribute::
>>> _ = web_shop.categories.pop(web_shop.categories.index(category2))
>>> _ = web_shop.products.pop(web_shop.products.index(product2))
>>> _ = web_shop.attributes.pop(web_shop.attributes.index(attribute2))
>>> web_shop.save()
Run VSF update::
>>> es.reset_mock()
>>> Cron = Model.get('ir.cron')
>>> cron_sync, = Cron.find([
... ('method', '=', 'web.shop|vsf_update'),
... ])
>>> cron_sync.click('run_once')
>>> es.index.call_count
5
>>> es.delete.call_count
3

View File

@@ -0,0 +1,910 @@
# 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 contextlib import contextmanager
from decimal import Decimal
from unittest.mock import ANY, patch
from trytond.modules.company.tests import (
CompanyTestMixin, create_company, set_company)
from trytond.modules.web_shop_vue_storefront.exceptions import LoginException
from trytond.pool import Pool
from trytond.protocols.wrappers import exceptions
from trytond.tests.test_tryton import ModuleTestCase, with_transaction
from trytond.transaction import Transaction
CUSTOMER = {
'email': 'customer@example.com',
'firstname': 'John',
'lastname': 'Doe',
}
ADDRESS = {
'region': {
'region': None,
},
'country_id': "US",
'street': [
"Cliff Street",
"300"
],
'telephone': '+1 202-555-0148',
'postcode': '18503',
'city': "Scranton",
'firstname': CUSTOMER['firstname'],
'lastname': CUSTOMER['lastname'],
}
ADDRESS_COMPANY = ADDRESS.copy()
ADDRESS_COMPANY['company'] = 'Saber'
ADDRESS_COMPANY['vat_id'] = 'BE0500923836'
class WebVueStorefrontTestCase(CompanyTestMixin, ModuleTestCase):
'Test Web Shop Vue Storefront module'
module = 'web_shop_vue_storefront'
extras = [
'product_attribute',
'product_image',
'sale_promotion_coupon',
'sale_shipment_cost',
'carrier',
]
maxDiff = None
@contextmanager
def create_web_shop(self):
pool = Pool()
WebShop = pool.get('web.shop')
Location = pool.get('stock.location')
Party = pool.get('party.party')
company = create_company()
warehouse, = Location.search([('type', '=', 'warehouse')], limit=1)
guest_party = Party(name="Guest")
guest_party.save()
web_shop = WebShop(name="Web Shop")
web_shop.company = company
web_shop.currency = company.currency
web_shop.warehouses = [warehouse]
web_shop.type = 'vsf'
web_shop.guest_party = guest_party
web_shop.save()
with Transaction().set_context(**web_shop.get_context()):
yield web_shop
def create_product(self, web_shop, quantity=0, code="CODE"):
pool = Pool()
Template = pool.get('product.template')
Product = pool.get('product.product')
Category = pool.get('product.category')
Uom = pool.get('product.uom')
Location = pool.get('stock.location')
Move = pool.get('stock.move')
unit, = Uom.search([('name', '=', "Unit")], limit=1)
account_category = Category(name="Category", accounting=True)
account_category.save()
template = Template(name="Product")
template.type = 'goods'
template.list_price = Decimal(100)
template.default_uom = unit
template.salable = True
template.sale_uom = unit
template.products = [Product(suffix_code=code, web_shops=[web_shop])]
template.account_category = account_category
template.save()
product, = template.products
if quantity:
supplier, = Location.search([('code', '=', 'SUP')])
storage, = Location.search([('code', '=', 'STO')])
with set_company(web_shop.company):
move = Move(product=product)
move.unit = unit
move.quantity = quantity
move.from_location = supplier
move.to_location = storage
move.unit_price = Decimal(50)
move.currency = web_shop.company.currency
move.save()
Move.do([move])
Product.set_vsf_identifier([product])
return product
def create_coupon(self, code='CODE'):
pool = Pool()
Promotion = pool.get('sale.promotion')
Coupon = pool.get('sale.promotion.coupon')
promotion = Promotion(name="10%")
promotion.formula = '0.9 * unit_price'
promotion.coupons = coupon, = [Coupon()]
coupon.numbers = [{'number': code}]
promotion.save()
def create_carrier(
self, name='Carrier', product_name="Delivery",
price=Decimal('10')):
pool = Pool()
Carrier = pool.get('carrier')
Party = pool.get('party.party')
Template = pool.get('product.template')
Product = pool.get('product.product')
Category = pool.get('product.category')
Uom = pool.get('product.uom')
unit, = Uom.search([('name', '=', "Unit")], limit=1)
account_category = Category(name="Service", accounting=True)
account_category.save()
template = Template(name=product_name)
template.type = 'service'
template.list_price = price
template.default_uom = template.sale_uom = unit
template.salable = True
template.products = [Product()]
template.account_category = account_category
template.save()
party = Party(name=name)
party.save()
carrier = Carrier()
carrier.party = party
carrier.carrier_product, = template.products
carrier.save()
return carrier
@with_transaction(user=0)
def test_user_create(self):
pool = Pool()
User = pool.get('web.user')
with self.create_web_shop() as web_shop:
result = web_shop.POST_vsf_user_create({
"customer": CUSTOMER,
"password": "SecretPassword"
})
users = User.search([])
self.assertEqual(result, {
"email": CUSTOMER['email'],
"firstname": CUSTOMER['firstname'],
"lastname": CUSTOMER['lastname'],
"addresses": [],
})
self.assertEqual(len(users), 1)
@with_transaction(user=0)
def test_user_login(self):
with self.create_web_shop() as web_shop:
web_shop.POST_vsf_user_create({
"customer": CUSTOMER,
"password": "TopSecretPassword",
})
result = web_shop.POST_vsf_user_login({
"username": CUSTOMER['email'],
"password": "TopSecretPassword",
})
self.assertTrue(result)
@with_transaction(user=0)
def test_user_login_wrong_password(self):
with self.create_web_shop() as web_shop:
web_shop.POST_vsf_user_create({
"customer": CUSTOMER,
"password": "TopSecretPassword",
})
with self.assertRaises(LoginException):
web_shop.POST_vsf_user_login({
"username": CUSTOMER['email'],
"password": "Bad",
})
@with_transaction(user=0)
def test_user_reset_password(self):
pool = Pool()
User = pool.get('web.user')
with self.create_web_shop() as web_shop:
web_shop.POST_vsf_user_create({
"customer": CUSTOMER,
"password": "SecretPassword",
})
with patch.object(User, 'reset_password') as reset_password:
result = web_shop.POST_vsf_user_reset_password({
"email": CUSTOMER['email'],
})
self.assertFalse(result)
reset_password.assert_called_once_with(ANY)
@with_transaction(user=0)
def test_user_change_password(self):
with self.create_web_shop() as web_shop:
web_shop.POST_vsf_user_create({
"customer": CUSTOMER,
"password": "OldPassword",
})
token = web_shop.POST_vsf_user_login({
"username": CUSTOMER['email'],
"password": "OldPassword",
})
result = web_shop.POST_vsf_user_change_password({
"currentPassword": "OldPassword",
"newPassword": "NewPassword",
}, token=token)
self.assertFalse(result)
@with_transaction(user=0)
def test_user_change_password_wrong_token(self):
with self.create_web_shop() as web_shop:
web_shop.POST_vsf_user_create({
"customer": CUSTOMER,
"password": "OldPassword",
})
with self.assertRaises(exceptions.Unauthorized):
web_shop.POST_vsf_user_change_password({
"currentPassword": "BadPassword",
"newPassword": "NewPassword",
}, 'wrong token')
@with_transaction(user=0)
def test_user_change_password_wrong_password(self):
with self.create_web_shop() as web_shop:
web_shop.POST_vsf_user_create({
"customer": CUSTOMER,
"password": "OldPassword",
})
token = web_shop.POST_vsf_user_login({
"username": CUSTOMER['email'],
"password": "OldPassword",
})
with self.assertRaises(LoginException):
web_shop.POST_vsf_user_change_password({
"currentPassword": "BadPassword",
"newPassword": "NewPassword",
}, token=token)
@with_transaction(user=0)
def test_user_order_history(self):
pool = Pool()
Country = pool.get('country.country')
Country(name="US", code="US").save()
with self.create_web_shop() as web_shop:
self.create_product(web_shop)
web_shop.POST_vsf_user_create({
"customer": CUSTOMER,
"password": "TopSecretPassword",
})
token = web_shop.POST_vsf_user_login({
"username": CUSTOMER['email'],
"password": "TopSecretPassword",
})
cart = web_shop.POST_vsf_cart_create(None, token=token)
web_shop.POST_vsf_order_create({
'products': [{
'sku': 'CODE',
'qty': 2,
}],
'addressInformation': {
'shippingAddress': ADDRESS,
'billingAddress': ADDRESS_COMPANY,
'shipping_method_code': None,
'shipping_carrier_code': None,
'payment_method_code': 'cashondelivery',
'payment_method_additional': {},
},
}, cart, token=token)
items = web_shop.GET_vsf_user_order_history(None, token=token)
self.assertEqual(items, {
'items': [{
'entity_id': ANY,
'increment_id': ANY,
'created_at': ANY,
'customer_firstname': CUSTOMER['firstname'],
'customer_lastname': CUSTOMER['lastname'],
'grand_total': 200,
'status': "Confirmed",
'items': [{
'name': "Product",
'sku': 'CODE',
'price_incl_tax': 100,
'qty_ordered': 2,
'row_total_incl_tax': 200,
}],
}],
})
@with_transaction(user=0)
def test_user_order_history_wrong_token(self):
with self.create_web_shop() as web_shop:
with self.assertRaises(exceptions.Unauthorized):
web_shop.GET_vsf_user_order_history(None, 'wrong token')
@with_transaction(user=0)
def test_user_me(self):
pool = Pool()
Country = pool.get('country.country')
Country(name="US", code="US").save()
with self.create_web_shop() as web_shop:
web_shop.POST_vsf_user_create({
"customer": CUSTOMER,
"password": "TopSecretPassword",
})
token = web_shop.POST_vsf_user_login({
"username": CUSTOMER['email'],
"password": "TopSecretPassword",
})
result = web_shop.GET_vsf_user_me(None, token=token)
data = {'customer': CUSTOMER.copy()}
data['customer']['addresses'] = []
self.assertEqual(result, data['customer'])
data = {'customer': CUSTOMER.copy()}
data['customer']['addresses'] = [ADDRESS_COMPANY.copy()]
result = web_shop.POST_vsf_user_me(data, token=token)
data['customer']['addresses'][0]['id'] = ANY
data['customer']['addresses'][0].pop('region')
self.assertEqual(result, data['customer'])
@with_transaction(user=0)
def test_user_me_wrong_token(self):
with self.create_web_shop() as web_shop:
with self.assertRaises(exceptions.Unauthorized):
web_shop.GET_vsf_user_me(None, 'wrong token')
with self.assertRaises(exceptions.Unauthorized):
web_shop.POST_vsf_user_me({}, 'wrong token')
@with_transaction(user=0)
def test_user_me_change_address(self):
pool = Pool()
Address = pool.get('party.address')
Country = pool.get('country.country')
Country(name="US", code="US").save()
with self.create_web_shop() as web_shop:
web_shop.POST_vsf_user_create({
"customer": CUSTOMER,
"password": "TopSecretPassword",
})
token = web_shop.POST_vsf_user_login({
"username": CUSTOMER['email'],
"password": "TopSecretPassword",
})
data = {'customer': CUSTOMER.copy()}
data['customer']['addresses'] = [ADDRESS_COMPANY]
result = web_shop.POST_vsf_user_me(data, token=token)
data = {'customer': CUSTOMER.copy()}
address = ADDRESS.copy()
address['lastname'] = "Scott"
data['customer']['addresses'] = [address]
result = web_shop.POST_vsf_user_me(
{"customer": result}, token=token)
inactive_addresses = Address.search([('active', '=', False)])
self.assertEqual(len(inactive_addresses), 1)
@with_transaction(user=0)
def test_stock_check(self):
with self.create_web_shop() as web_shop:
product = self.create_product(web_shop, quantity=10)
result = web_shop.GET_vsf_stock_check(None, product.vsf_sku)
self.assertEqual(result, {
'product_id': product.vsf_identifier.id,
'qty': 10,
'is_in_stock': True,
})
@with_transaction(user=0)
def test_stock_list(self):
with self.create_web_shop() as web_shop:
product1 = self.create_product(web_shop, quantity=10)
product2 = self.create_product(web_shop, quantity=0, code="CODE2")
result = web_shop.GET_vsf_stock_list(
None, ','.join([p.vsf_sku for p in [product1, product2]]))
self.assertEqual(result, [{
'product_id': product1.vsf_identifier.id,
'qty': 10,
'is_in_stock': True,
}, {
'product_id': product2.vsf_identifier.id,
'qty': 0,
'is_in_stock': False,
}])
@with_transaction(user=0)
def test_cart_create_without_token(self):
with self.create_web_shop() as web_shop:
cart = web_shop.POST_vsf_cart_create(None)
self.assertIsInstance(cart, str)
@with_transaction(user=0)
def test_cart_create_with_token(self):
with self.create_web_shop() as web_shop:
web_shop.POST_vsf_user_create({
"customer": CUSTOMER,
"password": "TopSecretPassword",
})
token = web_shop.POST_vsf_user_login({
"username": CUSTOMER['email'],
"password": "TopSecretPassword",
})
cart = web_shop.POST_vsf_cart_create(None, token=token)
self.assertIsInstance(cart, int)
@with_transaction(user=0)
def test_cart_pull_without_token(self):
with self.create_web_shop() as web_shop:
self.create_product(web_shop)
cart = web_shop.POST_vsf_cart_create(None)
web_shop.POST_vsf_cart_update({
'cartItem': {
'sku': 'CODE',
'qty': 1,
},
}, cart)
items = web_shop.GET_vsf_cart_pull(None, cart)
self.assertEqual(items, [{
'item_id': ANY,
'sku': 'CODE',
'qty': 1,
'name': 'Product',
'price': 100,
'product_type': 'simple',
'quote_id': ANY,
'product_option': {
'extension_attributes': {},
},
}])
@with_transaction(user=0)
def test_cart_pull_with_token(self):
with self.create_web_shop() as web_shop:
self.create_product(web_shop)
web_shop.POST_vsf_user_create({
"customer": CUSTOMER,
"password": "TopSecretPassword",
})
token = web_shop.POST_vsf_user_login({
"username": CUSTOMER['email'],
"password": "TopSecretPassword",
})
cart = web_shop.POST_vsf_cart_create(None, token=token)
web_shop.POST_vsf_cart_update({
'cartItem': {
'sku': 'CODE',
'qty': 1,
},
}, cart, token=token)
items = web_shop.GET_vsf_cart_pull(None, cart, token=token)
self.assertEqual(items, [{
'item_id': ANY,
'sku': 'CODE',
'qty': 1,
'name': 'Product',
'price': 100,
'product_type': 'simple',
'quote_id': ANY,
'product_option': {
'extension_attributes': {},
},
}])
@with_transaction(user=0)
def test_cart_update_without_token(self):
pool = Pool()
SaleLine = pool.get('sale.line')
with self.create_web_shop() as web_shop:
self.create_product(web_shop)
cart = web_shop.POST_vsf_cart_create(None)
item = web_shop.POST_vsf_cart_update({
'cartItem': {
'sku': 'CODE',
'qty': 1,
},
}, cart)
self.assertEqual(item, {
'item_id': ANY,
'sku': 'CODE',
'qty': 1,
'name': 'Product',
'price': 100,
'product_type': 'simple',
'quote_id': ANY,
'product_option': {
'extension_attributes': {},
},
})
sale_lines = SaleLine.search([])
self.assertEqual(len(sale_lines), 1)
@with_transaction(user=0)
def test_cart_update_with_token(self):
pool = Pool()
SaleLine = pool.get('sale.line')
with self.create_web_shop() as web_shop:
self.create_product(web_shop)
web_shop.POST_vsf_user_create({
"customer": CUSTOMER,
"password": "TopSecretPassword",
})
token = web_shop.POST_vsf_user_login({
"username": CUSTOMER['email'],
"password": "TopSecretPassword",
})
cart = web_shop.POST_vsf_cart_create(None, token=token)
item = web_shop.POST_vsf_cart_update({
'cartItem': {
'sku': 'CODE',
'qty': 1,
},
}, cart, token=token)
self.assertEqual(item, {
'item_id': ANY,
'sku': 'CODE',
'qty': 1,
'name': 'Product',
'price': 100,
'product_type': 'simple',
'quote_id': ANY,
'product_option': {
'extension_attributes': {},
},
})
sale_lines = SaleLine.search([])
self.assertEqual(len(sale_lines), 1)
@with_transaction(user=0)
def test_cart_update2(self):
pool = Pool()
SaleLine = pool.get('sale.line')
with self.create_web_shop() as web_shop:
self.create_product(web_shop)
cart = web_shop.POST_vsf_cart_create(None)
item = web_shop.POST_vsf_cart_update({
'cartItem': {
'sku': 'CODE',
'qty': 1,
},
}, cart)
item = web_shop.POST_vsf_cart_update({
'cartItem': {
'sku': 'CODE',
'qty': 2,
'item_id': item['item_id'],
},
}, cart)
self.assertEqual(item, {
'item_id': ANY,
'sku': 'CODE',
'qty': 2,
'name': 'Product',
'price': 100,
'product_type': 'simple',
'quote_id': ANY,
'product_option': {
'extension_attributes': {},
},
})
sale_lines = SaleLine.search([])
self.assertEqual(len(sale_lines), 1)
@with_transaction(user=0)
def test_cart_delete(self):
pool = Pool()
SaleLine = pool.get('sale.line')
with self.create_web_shop() as web_shop:
self.create_product(web_shop)
cart = web_shop.POST_vsf_cart_create(None)
item = web_shop.POST_vsf_cart_update({
'cartItem': {
'sku': 'CODE',
'qty': 1,
},
}, cart)
result = web_shop.POST_vsf_cart_delete({
'cartItem': {
'sku': 'CODE',
'qty': 1,
'item_id': item['item_id'],
},
}, cart)
self.assertTrue(result)
sale_lines = SaleLine.search([])
self.assertEqual(len(sale_lines), 0)
@with_transaction(user=0)
def test_cart_apply_coupon(self):
with self.create_web_shop() as web_shop:
self.create_coupon()
cart = web_shop.POST_vsf_cart_create(None)
result = web_shop.POST_vsf_cart_apply_coupon(None, cart, 'CODE')
self.assertTrue(result)
@with_transaction(user=0)
def test_cart_delete_coupon(self):
with self.create_web_shop() as web_shop:
self.create_coupon()
cart = web_shop.POST_vsf_cart_create(None)
web_shop.POST_vsf_cart_apply_coupon(None, cart, 'CODE')
result = web_shop.POST_vsf_cart_delete_coupon(None, cart)
self.assertTrue(result)
@with_transaction(user=0)
def test_cart_coupon(self):
with self.create_web_shop() as web_shop:
self.create_coupon()
cart = web_shop.POST_vsf_cart_create(None)
web_shop.POST_vsf_cart_apply_coupon(None, cart, 'CODE')
result = web_shop.POST_vsf_cart_coupon(None, cart)
self.assertEqual(result, 'CODE')
@with_transaction(user=0)
def test_cart_coupon_empty(self):
with self.create_web_shop() as web_shop:
cart = web_shop.POST_vsf_cart_create(None)
result = web_shop.POST_vsf_cart_coupon(None, cart)
self.assertEqual(result, '')
@with_transaction(user=0)
def test_cart_totals(self):
with self.create_web_shop() as web_shop:
self.create_product(web_shop)
cart = web_shop.POST_vsf_cart_create(None)
web_shop.POST_vsf_cart_update({
'cartItem': {
'sku': 'CODE',
'qty': 1,
},
}, cart)
totals = web_shop.GET_vsf_cart_totals(None, cart)
self.assertEqual(totals, {
'grand_total': 100,
'items': [{
'item_id': ANY,
'sku': 'CODE',
'qty': 1,
'name': 'Product',
'price': 100,
'product_type': 'simple',
'quote_id': ANY,
'product_option': {
'extension_attributes': {
},
},
}],
'total_segments': [{
'code': 'subtotal',
'title': ANY,
'value': 100,
}, {
'code': 'tax',
'title': ANY,
'value': 0,
}, {
'code': 'grand_total',
'title': ANY,
'value': 100,
}],
})
@with_transaction(user=0)
def test_cart_payment_methods(self):
with self.create_web_shop() as web_shop:
cart = web_shop.POST_vsf_cart_create(None)
result = web_shop.GET_vsf_cart_payment_methods(None, cart)
self.assertEqual(result, [])
@with_transaction(user=0)
def test_cart_shipping_methods(self):
pool = Pool()
Country = pool.get('country.country')
Country(name="US", code="US").save()
with self.create_web_shop() as web_shop:
carrier = self.create_carrier()
self.create_product(web_shop)
cart = web_shop.POST_vsf_cart_create(None)
web_shop.POST_vsf_cart_update({
'cartItem': {
'sku': 'CODE',
'qty': 1,
},
}, cart)
methods = web_shop.POST_vsf_cart_shipping_methods(
{'address': {'country_id': 'US'}}, cart)
self.assertEqual(methods, [{
'carrier_code': str(carrier.id),
'method_code': str(carrier.id),
'carrier_title': "Carrier",
'method_title': "Delivery",
'price_incl_tax': Decimal(10),
}])
@with_transaction(user=0)
def test_cart_shipping_information(self):
pool = Pool()
Country = pool.get('country.country')
Country(name="US", code="US").save()
with self.create_web_shop() as web_shop:
carrier = self.create_carrier()
self.create_product(web_shop)
cart = web_shop.POST_vsf_cart_create(None)
web_shop.POST_vsf_cart_update({
'cartItem': {
'sku': 'CODE',
'qty': 1,
},
}, cart)
information = web_shop.POST_vsf_cart_shipping_information({
'addressInformation': {
'shipping_address': {
'country_id': 'US',
},
'shipping_method_code': str(carrier.id),
'shipping_carrier_code': str(carrier.id),
},
}, cart)
self.assertEqual(information, {
'grand_total': 110,
'items': ANY,
'total_segments': [{
'code': 'subtotal',
'title': ANY,
'value': 100,
}, {
'code': 'shipping',
'title': ANY,
'value': 10,
}, {
'code': 'tax',
'title': ANY,
'value': 0,
}, {
'code': 'grand_total',
'title': ANY,
'value': 110,
}],
})
@with_transaction(user=0)
def test_order_create(self):
pool = Pool()
Sale = pool.get('sale.sale')
Country = pool.get('country.country')
Country(name="US", code="US").save()
with self.create_web_shop() as web_shop:
carrier = self.create_carrier()
self.create_product(web_shop)
web_shop.POST_vsf_user_create({
"customer": CUSTOMER,
"password": "TopSecretPassword",
})
token = web_shop.POST_vsf_user_login({
"username": CUSTOMER['email'],
"password": "TopSecretPassword",
})
cart = web_shop.POST_vsf_cart_create(None, token=token)
web_shop.POST_vsf_cart_update({
'cartItem': {
'sku': 'CODE',
'qty': 1,
},
}, cart, token=token)
result = web_shop.POST_vsf_order_create({
'products': [{
'sku': 'CODE',
'qty': 1,
}],
'addressInformation': {
'shippingAddress': ADDRESS,
'billingAddress': ADDRESS_COMPANY,
'shipping_method_code': str(carrier.id),
'shipping_carrier_code': str(carrier.id),
'payment_method_code': 'cashondelivery',
'payment_method_additional': {},
},
}, cart, token=token)
self.assertEqual(result, 'OK')
sale, = Sale.search([])
self.assertEqual(sale.state, 'confirmed')
self.assertEqual(len(sale.lines), 2)
self.assertEqual(sale.total_amount, Decimal(110))
@with_transaction(user=0)
def test_order_create_from_guest(self):
pool = Pool()
Sale = pool.get('sale.sale')
Country = pool.get('country.country')
Country(name="US", code="US").save()
with self.create_web_shop() as web_shop:
carrier = self.create_carrier()
self.create_product(web_shop)
cart = web_shop.POST_vsf_cart_create(None)
web_shop.POST_vsf_cart_update({
'cartItem': {
'sku': 'CODE',
'qty': 1,
},
}, cart)
web_shop.POST_vsf_user_create({
"customer": CUSTOMER,
"password": "TopSecretPassword",
})
token = web_shop.POST_vsf_user_login({
"username": CUSTOMER['email'],
"password": "TopSecretPassword",
})
result = web_shop.POST_vsf_order_create({
'products': [{
'sku': 'CODE',
'qty': 1,
}],
'addressInformation': {
'shippingAddress': ADDRESS,
'billingAddress': ADDRESS_COMPANY,
'shipping_method_code': str(carrier.id),
'shipping_carrier_code': str(carrier.id),
'payment_method_code': 'cashondelivery',
'payment_method_additional': {},
},
}, cart, token=token)
self.assertEqual(result, 'OK')
sale, = Sale.search([])
self.assertNotEqual(sale.party, web_shop.guest_party)
self.assertEqual(sale.state, 'confirmed')
self.assertEqual(len(sale.lines), 2)
self.assertEqual(sale.total_amount, Decimal(110))
del ModuleTestCase

View File

@@ -0,0 +1,8 @@
# 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 trytond.tests.test_tryton import load_doc_tests
def load_tests(*args, **kwargs):
return load_doc_tests(__name__, __file__, *args, **kwargs)

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.
class AnyDictWith(dict):
def __eq__(self, other):
if not isinstance(other, dict):
return False
items = list(sorted(filter(lambda i: i[0] in self, other.items())))
return list(sorted(self.items())) == items