~homeworkprod/byceps

e8d2046f2109dc9199ec2d7e927c0a8946785048 — Jochen Kupperschmidt a month ago 560211d
Attach shop to brand

DDL:

    ALTER TABLE shops ADD COLUMN brand_id text;

    -- At this point, manually set a brand for each shop.

    ALTER TABLE shops ALTER COLUMN brand_id SET NOT NULL;

    ALTER TABLE shops ADD CONSTRAINT shops_brand_id_fkey FOREIGN KEY (brand_id) REFERENCES brands (id);

    CREATE INDEX ix_shops_brand_id ON shops USING btree (brand_id);
M byceps/blueprints/admin/shop/shop/forms.py => byceps/blueprints/admin/shop/shop/forms.py +7 -0
@@ 9,6 9,7 @@ byceps.blueprints.admin.shop.shop.forms
from wtforms import SelectField, StringField
from wtforms.validators import InputRequired, Length

from .....services.brand import service as brand_service
from .....services.email import service as email_service
from .....util.l10n import LocalizedForm



@@ 17,6 18,11 @@ class _BaseForm(LocalizedForm):
    title = StringField('Titel', validators=[Length(min=1, max=40)])
    email_config_id = SelectField('E-Mail-Konfiguration', validators=[InputRequired()])

    def set_brand_choices(self):
        brands = brand_service.get_all_brands()
        brands.sort(key=lambda brand: brand.title)
        self.brand_id.choices = [(brand.id, brand.title) for brand in brands]

    def set_email_config_choices(self):
        configs = email_service.get_all_configs()
        configs.sort(key=lambda config: config.id)


@@ 25,6 31,7 @@ class _BaseForm(LocalizedForm):

class CreateForm(_BaseForm):
    id = StringField('ID', validators=[InputRequired()])
    brand_id = SelectField('Marke', validators=[InputRequired()])


class UpdateForm(_BaseForm):

M byceps/blueprints/admin/shop/shop/templates/admin/shop/shop/create_form.html => byceps/blueprints/admin/shop/shop/templates/admin/shop/shop/create_form.html +1 -0
@@ 16,6 16,7 @@
  <form action="{{ url_for('.create') }}" method="post">
    {% call form_fieldset() %}
      {{ form_field(form.id, maxlength=40, required='required', autofocus='autofocus') }}
      {{ form_field(form.brand_id, required='required') }}
      {{ form_field(form.title, maxlength=40, required='required') }}
      {{ form_field(form.email_config_id, required='required') }}
    {% endcall %}

M byceps/blueprints/admin/shop/shop/views.py => byceps/blueprints/admin/shop/shop/views.py +4 -1
@@ 69,6 69,7 @@ def view(shop_id):
def create_form(erroneous_form=None):
    """Show form to create a shop."""
    form = erroneous_form if erroneous_form else CreateForm()
    form.set_brand_choices()
    form.set_email_config_choices()

    return {


@@ 81,16 82,18 @@ def create_form(erroneous_form=None):
def create():
    """Create a shop."""
    form = CreateForm(request.form)
    form.set_brand_choices()
    form.set_email_config_choices()

    if not form.validate():
        return create_form(form)

    shop_id = form.id.data.strip().lower()
    brand_id = form.brand_id.data
    title = form.title.data.strip()
    email_config_id = form.email_config_id.data

    shop = shop_service.create_shop(shop_id, title, email_config_id)
    shop = shop_service.create_shop(shop_id, brand_id, title, email_config_id)

    flash_success(f'Der Shop "{shop.title}" wurde angelegt.')
    return redirect_to('.index')

M byceps/services/shop/shop/models.py => byceps/services/shop/shop/models.py +8 -1
@@ 9,6 9,7 @@ byceps.services.shop.shop.models
from sqlalchemy.ext.mutable import MutableDict

from ....database import db
from ....typing import BrandID
from ....util.instances import ReprBuilder

from .transfer.models import ShopID


@@ 20,15 21,21 @@ class Shop(db.Model):
    __tablename__ = 'shops'

    id = db.Column(db.UnicodeText, primary_key=True)
    brand_id = db.Column(db.UnicodeText, db.ForeignKey('brands.id'), index=True, nullable=False)
    title = db.Column(db.UnicodeText, unique=True, nullable=False)
    email_config_id = db.Column(db.UnicodeText, db.ForeignKey('email_configs.id'), nullable=False)
    archived = db.Column(db.Boolean, default=False, nullable=False)
    extra_settings = db.Column(MutableDict.as_mutable(db.JSONB))

    def __init__(
        self, shop_id: ShopID, title: str, email_config_id: str
        self,
        shop_id: ShopID,
        brand_id: BrandID,
        title: str,
        email_config_id: str,
    ) -> None:
        self.id = shop_id
        self.brand_id = brand_id
        self.title = title
        self.email_config_id = email_config_id


M byceps/services/shop/shop/service.py => byceps/services/shop/shop/service.py +6 -2
@@ 9,6 9,7 @@ byceps.services.shop.shop.service
from typing import List, Optional, Set

from ....database import db
from ....typing import BrandID

from .models import Shop as DbShop
from .transfer.models import Shop, ShopID


@@ 18,9 19,11 @@ class UnknownShopId(ValueError):
    pass


def create_shop(shop_id: ShopID, title: str, email_config_id: str) -> Shop:
def create_shop(
    shop_id: ShopID, brand_id: BrandID, title: str, email_config_id: str
) -> Shop:
    """Create a shop."""
    shop = DbShop(shop_id, title, email_config_id)
    shop = DbShop(shop_id, brand_id, title, email_config_id)

    db.session.add(shop)
    db.session.commit()


@@ 146,6 149,7 @@ def _db_entity_to_shop(shop: DbShop) -> Shop:

    return Shop(
        shop.id,
        shop.brand_id,
        shop.title,
        shop.email_config_id,
        shop.archived,

M byceps/services/shop/shop/transfer/models.py => byceps/services/shop/shop/transfer/models.py +3 -0
@@ 9,6 9,8 @@ byceps.services.shop.shop.transfer.models
from dataclasses import dataclass
from typing import Any, Dict, NewType

from .....typing import BrandID


ShopID = NewType('ShopID', str)



@@ 16,6 18,7 @@ ShopID = NewType('ShopID', str)
@dataclass(frozen=True)
class Shop:
    id: ShopID
    brand_id: BrandID
    title: str
    email_config_id: str
    archived: bool

M tests/integration/announce/irc/test_shop_order.py => tests/integration/announce/irc/test_shop_order.py +2 -2
@@ 119,9 119,9 @@ def shop_admin(make_user):


@pytest.fixture(scope='module')
def shop(app, email_config):
def shop(app, brand, email_config):
    shop = shop_service.create_shop(
        'popup-store', 'Popup Store', email_config.id
        'popup-store', brand.id, 'Popup Store', email_config.id
    )

    yield shop

M tests/integration/blueprints/admin/shop/conftest.py => tests/integration/blueprints/admin/shop/conftest.py +4 -2
@@ 13,8 13,10 @@ from byceps.services.shop.storefront import service as storefront_service


@pytest.fixture(scope='module')
def shop(email_config):
    shop = shop_service.create_shop('shop-01', 'Some Shop', email_config.id)
def shop(brand, email_config):
    shop = shop_service.create_shop(
        'shop-01', brand.id, 'Some Shop', email_config.id
    )

    yield shop


M tests/integration/blueprints/admin/shop/shop/test_create_shop.py => tests/integration/blueprints/admin/shop/shop/test_create_shop.py +6 -1
@@ 26,13 26,14 @@ def shop_admin_client(make_client, admin_app, shop_admin):
    return make_client(admin_app, user_id=shop_admin.id)


def test_create_shop(email_config, shop_admin_client):
def test_create_shop(brand, email_config, shop_admin_client):
    shop_id = 'acme'
    assert shop_service.find_shop(shop_id) is None

    url = '/admin/shop/shop/shops'
    form_data = {
        'id': shop_id,
        'brand_id': brand.id,
        'title': 'ACME',
        'email_config_id': email_config.id,
    }


@@ 41,5 42,9 @@ def test_create_shop(email_config, shop_admin_client):
    shop = shop_service.find_shop(shop_id)
    assert shop is not None
    assert shop.id == shop_id
    assert shop.brand_id == brand.id
    assert shop.title == 'ACME'
    assert shop.email_config_id == email_config.id

    # Clean up.
    shop_service.delete_shop(shop.id)

M tests/integration/blueprints/site/shop/order/test_views.py => tests/integration/blueprints/site/shop/order/test_views.py +2 -2
@@ 38,8 38,8 @@ COMMON_FORM_DATA = {


@pytest.fixture
def shop(email_config, admin_user):
    shop = create_shop('shop-1')
def shop(brand, email_config, admin_user):
    shop = create_shop('shop-1', brand.id)
    snippet_id = create_shop_fragment(
        shop.id, admin_user.id, 'payment_instructions', 'Send all ur moneyz!'
    )

M tests/integration/blueprints/site/shop/orders/test_views.py => tests/integration/blueprints/site/shop/orders/test_views.py +4 -4
@@ 25,8 25,8 @@ from tests.integration.services.shop.helpers import (


@pytest.fixture
def shop1(admin_app, email_config, admin_user):
    shop = create_shop('shop-1')
def shop1(admin_app, brand, email_config, admin_user):
    shop = create_shop('shop-1', brand.id)
    snippet_id = create_payment_instructions_snippet(shop.id, admin_user.id)

    yield shop


@@ 36,8 36,8 @@ def shop1(admin_app, email_config, admin_user):


@pytest.fixture
def shop2(admin_app, email_config):
    shop = create_shop('shop-2')
def shop2(admin_app, brand, email_config):
    shop = create_shop('shop-2', brand.id)

    yield shop


M tests/integration/services/shop/article/test_article_number_generation.py => tests/integration/services/shop/article/test_article_number_generation.py +8 -4
@@ 12,15 12,19 @@ from byceps.services.shop.shop import service as shop_service


@pytest.fixture(scope='module')
def shop1(email_config):
    shop = shop_service.create_shop('shop-01', 'Some Shop', email_config.id)
def shop1(brand, email_config):
    shop = shop_service.create_shop(
        'shop-01', brand.id, 'Some Shop', email_config.id
    )
    yield shop
    shop_service.delete_shop(shop.id)


@pytest.fixture(scope='module')
def shop2(email_config):
    shop = shop_service.create_shop('shop-02', 'Another Shop', email_config.id)
def shop2(brand, email_config):
    shop = shop_service.create_shop(
        'shop-02', brand.id, 'Another Shop', email_config.id
    )
    yield shop
    shop_service.delete_shop(shop.id)


M tests/integration/services/shop/conftest.py => tests/integration/services/shop/conftest.py +4 -2
@@ 14,8 14,10 @@ from byceps.services.shop.storefront import service as storefront_service


@pytest.fixture
def shop(email_config):
    shop = shop_service.create_shop('shop-01', 'Some Shop', email_config.id)
def shop(brand, email_config):
    shop = shop_service.create_shop(
        'shop-01', brand.id, 'Some Shop', email_config.id
    )
    yield shop
    shop_service.delete_shop(shop.id)


M tests/integration/services/shop/helpers.py => tests/integration/services/shop/helpers.py +4 -2
@@ 19,8 19,10 @@ from byceps.services.user.transfer.models import UserWithDetail
from tests.helpers import DEFAULT_EMAIL_CONFIG_ID


def create_shop(shop_id='shop-1', email_config_id=DEFAULT_EMAIL_CONFIG_ID):
    return shop_service.create_shop(shop_id, shop_id, email_config_id)
def create_shop(
    shop_id='shop-1', brand_id=None, email_config_id=DEFAULT_EMAIL_CONFIG_ID
):
    return shop_service.create_shop(shop_id, brand_id, shop_id, email_config_id)


def create_shop_fragment(shop_id, admin_id, name, body):

M tests/integration/services/shop/order/test_order_number_generation.py => tests/integration/services/shop/order/test_order_number_generation.py +8 -4
@@ 12,15 12,19 @@ from byceps.services.shop.shop import service as shop_service


@pytest.fixture(scope='module')
def shop1(email_config):
    shop = shop_service.create_shop('shop-01', 'Some Shop', email_config.id)
def shop1(brand, email_config):
    shop = shop_service.create_shop(
        'shop-01', brand.id, 'Some Shop', email_config.id
    )
    yield shop
    shop_service.delete_shop(shop.id)


@pytest.fixture(scope='module')
def shop2(email_config):
    shop = shop_service.create_shop('shop-02', 'Another Shop', email_config.id)
def shop2(brand, email_config):
    shop = shop_service.create_shop(
        'shop-02', brand.id, 'Another Shop', email_config.id
    )
    yield shop
    shop_service.delete_shop(shop.id)


M tests/integration/services/shop/order/test_service_orders_placed_by_user_for_shop.py => tests/integration/services/shop/order/test_service_orders_placed_by_user_for_shop.py +4 -4
@@ 17,8 17,8 @@ from tests.integration.services.shop.helpers import create_shop, create_orderer


@pytest.fixture
def storefront1(email_config):
    shop = create_shop('first-nice-shop')
def storefront1(brand, email_config):
    shop = create_shop('first-nice-shop', brand.id)
    order_number_sequence_id = (
        order_sequence_service.create_order_number_sequence(shop.id, 'LF-02-B')
    )


@@ 39,8 39,8 @@ def storefront1(email_config):


@pytest.fixture
def storefront2(email_config):
    shop = create_shop('second-nice-shop')
def storefront2(brand, email_config):
    shop = create_shop('second-nice-shop', brand.id)
    order_number_sequence_id = (
        order_sequence_service.create_order_number_sequence(shop.id, 'LF-03-B')
    )