From 660637522d9cc4e641a9b929a682fabec790389e Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sat, 10 Jun 2023 14:35:08 -0500 Subject: [PATCH] Add `CustomerShopper.corepos_customer_id` and refactor importers removes phone/email support for now..also change how we handle default/empty values for member start/end date.. --- .../corepos/office/importing/model.py | 31 +++++------ .../corepos/office/importing/rattail.py | 43 ++++++++-------- ...add_customershopper_corepos_customer_id.py | 51 +++++++++++++++++++ rattail_corepos/db/model/people.py | 39 +++++++++++++- rattail_corepos/emails.py | 8 +++ rattail_corepos/importing/corepos/api.py | 6 ++- rattail_corepos/importing/model.py | 9 ++++ 7 files changed, 150 insertions(+), 37 deletions(-) create mode 100644 rattail_corepos/db/alembic/versions/b025df7cf41b_add_customershopper_corepos_customer_id.py diff --git a/rattail_corepos/corepos/office/importing/model.py b/rattail_corepos/corepos/office/importing/model.py index 17bac9b..536ed65 100644 --- a/rattail_corepos/corepos/office/importing/model.py +++ b/rattail_corepos/corepos/office/importing/model.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2021 Lance Edgar +# Copyright © 2010-2023 Lance Edgar # # This file is part of Rattail. # @@ -121,7 +121,8 @@ class MemberImporter(ToCoreAPI): # 'modified', ] - empty_date_value = '0000-00-00 00:00:00' + #empty_date_value = '0000-00-00 00:00:00' + empty_date_value = '1900-01-01 00:00:00' def get_local_objects(self, host_data=None): return get_core_members(self.config, self.api, progress=self.progress) @@ -144,14 +145,14 @@ class MemberImporter(ToCoreAPI): if not self.customer_data_differs(local_data, host_data): diffs.remove('customers') - # also the start/end dates should be looked at more closely. if they - # contain the special '__omit__' value then we won't ever count as diff - if 'startDate' in self.fields and 'startDate' in diffs: - if host_data['startDate'] == '__omit__': - diffs.remove('startDate') - if 'endDate' in self.fields and 'endDate' in diffs: - if host_data['endDate'] == '__omit__': - diffs.remove('endDate') + # # also the start/end dates should be looked at more closely. if they + # # contain the special '__omit__' value then we won't ever count as diff + # if 'startDate' in self.fields and 'startDate' in diffs: + # if host_data['startDate'] == '__omit__': + # diffs.remove('startDate') + # if 'endDate' in self.fields and 'endDate' in diffs: + # if host_data['endDate'] == '__omit__': + # diffs.remove('endDate') return diffs @@ -220,11 +221,11 @@ class MemberImporter(ToCoreAPI): return data cardNo = data.pop('cardNo') - data = dict(data) - if data.get('startDate') == '__omit__': - data.pop('startDate') - if data.get('endDate') == '__omit__': - data.pop('endDate') + # data = dict(data) + # if data.get('startDate') == '__omit__': + # data.pop('startDate') + # if data.get('endDate') == '__omit__': + # data.pop('endDate') member = self.api.set_member(cardNo, **data) return member diff --git a/rattail_corepos/corepos/office/importing/rattail.py b/rattail_corepos/corepos/office/importing/rattail.py index 44d5de8..0a5f7ce 100644 --- a/rattail_corepos/corepos/office/importing/rattail.py +++ b/rattail_corepos/corepos/office/importing/rattail.py @@ -97,9 +97,9 @@ class MemberImporter(FromRattail, corepos_importing.model.MemberImporter): 'firstName', 'lastName', 'accountHolder', - 'phone', - 'altPhone', - 'email', + # 'phone', + # 'altPhone', + # 'email', ] def query(self): @@ -117,23 +117,24 @@ class MemberImporter(FromRattail, corepos_importing.model.MemberImporter): address = customer.addresses[0] if customer.addresses else None - people = [] - for i, person in enumerate(customer.people, 1): - phones = person.phones - phone1 = phones[0] if phones else None - phone2 = phones[1] if len(phones) > 1 else None - email = person.emails[0] if person.emails else None - people.append({ - 'customerID': str(person.corepos_customer_id), + shoppers = [] + for shopper in customer.shoppers: + person = shopper.person + # phones = person.phones + # phone1 = phones[0] if phones else None + # phone2 = phones[1] if len(phones) > 1 else None + # email = person.emails[0] if person.emails else None + shoppers.append({ + 'customerID': str(shopper.corepos_customer_id), 'firstName': person.first_name, 'lastName': person.last_name, - 'accountHolder': i == 1, - 'phone': phone1.number if phone1 else '', - 'altPhone': phone2.number if phone2 else '', - 'email': email.address if email else '', + 'accountHolder': shopper.shopper_number == 1, + # 'phone': phone1.number if phone1 else '', + # 'altPhone': phone2.number if phone2 else '', + # 'email': email.address if email else '', }) - member = customer.only_member(require=False) + member = self.app.get_member(customer) if member: if member.joined: start_date = member.joined.strftime('%Y-%m-%d 00:00:00') @@ -144,12 +145,14 @@ class MemberImporter(FromRattail, corepos_importing.model.MemberImporter): else: end_date = self.empty_date_value else: - start_date = '__omit__' - end_date = '__omit__' + # start_date = '__omit__' + # end_date = '__omit__' + start_date = self.empty_date_value + end_date = self.empty_date_value return { 'cardNo': customer.number, - 'customerAccountID': customer.id, + 'customerAccountID': str(customer.corepos_account_id or ''), 'addressFirstLine': address.street if address else '', 'addressSecondLine': address.street2 if address else '', 'city': address.city if address else '', @@ -157,7 +160,7 @@ class MemberImporter(FromRattail, corepos_importing.model.MemberImporter): 'zip': address.zipcode if address else '', 'startDate': start_date, 'endDate': end_date, - 'customers': people, + 'customers': shoppers, } diff --git a/rattail_corepos/db/alembic/versions/b025df7cf41b_add_customershopper_corepos_customer_id.py b/rattail_corepos/db/alembic/versions/b025df7cf41b_add_customershopper_corepos_customer_id.py new file mode 100644 index 0000000..600c2dc --- /dev/null +++ b/rattail_corepos/db/alembic/versions/b025df7cf41b_add_customershopper_corepos_customer_id.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8; -*- +"""add CustomerShopper.corepos_customer_id + +Revision ID: b025df7cf41b +Revises: ae74c537ea51 +Create Date: 2023-06-10 13:24:40.735959 + +""" + +# revision identifiers, used by Alembic. +revision = 'b025df7cf41b' +down_revision = 'ae74c537ea51' +branch_labels = None +depends_on = None + +from alembic import op +import sqlalchemy as sa +import rattail.db.types + + + +def upgrade(): + + # corepos_customer_shopper + op.create_table('corepos_customer_shopper', + sa.Column('uuid', sa.String(length=32), nullable=False), + sa.Column('corepos_customer_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['uuid'], ['customer_shopper.uuid'], name='corepos_customer_shopper_fk_shopper'), + sa.PrimaryKeyConstraint('uuid') + ) + op.create_table('corepos_customer_shopper_version', + sa.Column('uuid', sa.String(length=32), autoincrement=False, nullable=False), + sa.Column('corepos_customer_id', sa.Integer(), autoincrement=False, nullable=True), + sa.Column('transaction_id', sa.BigInteger(), autoincrement=False, nullable=False), + sa.Column('end_transaction_id', sa.BigInteger(), nullable=True), + sa.Column('operation_type', sa.SmallInteger(), nullable=False), + sa.PrimaryKeyConstraint('uuid', 'transaction_id') + ) + op.create_index(op.f('ix_corepos_customer_shopper_version_end_transaction_id'), 'corepos_customer_shopper_version', ['end_transaction_id'], unique=False) + op.create_index(op.f('ix_corepos_customer_shopper_version_operation_type'), 'corepos_customer_shopper_version', ['operation_type'], unique=False) + op.create_index(op.f('ix_corepos_customer_shopper_version_transaction_id'), 'corepos_customer_shopper_version', ['transaction_id'], unique=False) + + +def downgrade(): + + # corepos_customer_shopper + op.drop_index(op.f('ix_corepos_customer_shopper_version_transaction_id'), table_name='corepos_customer_shopper_version') + op.drop_index(op.f('ix_corepos_customer_shopper_version_operation_type'), table_name='corepos_customer_shopper_version') + op.drop_index(op.f('ix_corepos_customer_shopper_version_end_transaction_id'), table_name='corepos_customer_shopper_version') + op.drop_table('corepos_customer_shopper_version') + op.drop_table('corepos_customer_shopper') diff --git a/rattail_corepos/db/model/people.py b/rattail_corepos/db/model/people.py index a769d62..3d72baa 100644 --- a/rattail_corepos/db/model/people.py +++ b/rattail_corepos/db/model/people.py @@ -91,7 +91,8 @@ class CoreCustomer(model.Base): """)) corepos_account_id = sa.Column(sa.Integer(), nullable=True, doc=""" - ``Customers.customerAccountID`` value for this customer, within CORE-POS. + ``CustomerAccounts.customerAccountID`` value for this customer + account, within CORE-POS. """) corepos_card_number = sa.Column(sa.Integer(), nullable=True, doc=""" @@ -105,6 +106,42 @@ CoreCustomer.make_proxy(model.Customer, '_corepos', 'corepos_account_id') CoreCustomer.make_proxy(model.Customer, '_corepos', 'corepos_card_number') +class CoreCustomerShopper(model.Base): + """ + CORE-specific extensions to + :class:`~rattail:rattail.db.model.CustomerShopper`. + """ + __tablename__ = 'corepos_customer_shopper' + __table_args__ = ( + sa.ForeignKeyConstraint(['uuid'], ['customer_shopper.uuid'], + name='corepos_customer_shopper_fk_shopper'), + ) + __versioned__ = {} + + uuid = model.uuid_column(default=None) + shopper = orm.relationship( + model.CustomerShopper, doc=""" + Reference to the actual shopper record, which this one extends. + """, + cascade_backrefs=False, + backref=orm.backref( + '_corepos', doc=""" + Reference to the CORE-POS extension record for this customer. + """, + uselist=False, + cascade='all, delete-orphan', + cascade_backrefs=False)) + + corepos_customer_id = sa.Column(sa.Integer(), nullable=True, doc=""" + ``Customers.customerID`` value for this shopper, within CORE-POS. + """) + + def __str__(self): + return str(self.shopper) + +CoreCustomerShopper.make_proxy(model.CustomerShopper, '_corepos', 'corepos_customer_id') + + class CoreMember(model.Base): """ CORE-specific extensions to :class:`rattail:rattail.db.model.Member`. diff --git a/rattail_corepos/emails.py b/rattail_corepos/emails.py index b3be737..651ab69 100644 --- a/rattail_corepos/emails.py +++ b/rattail_corepos/emails.py @@ -62,6 +62,14 @@ class corepos_problems_invalid_person_numbers(ProblemReportEmail): } +class rattail_export_corepos_updates(ImporterEmail): + """ + Sent when a Rattail -> CORE-POS API export involves data changes. + """ + handler_spec = 'rattail_corepos.corepos.office.importing.rattail:FromRattailToCore' + abstract = False + + class rattail_import_corepos_api_updates(ImporterEmail): """ Sent when a CORE-POS API -> Rattail import involves data changes. diff --git a/rattail_corepos/importing/corepos/api.py b/rattail_corepos/importing/corepos/api.py index 8b12e6a..6e6e84e 100644 --- a/rattail_corepos/importing/corepos/api.py +++ b/rattail_corepos/importing/corepos/api.py @@ -136,6 +136,7 @@ class CustomerImporter(FromCOREPOSAPI, corepos_importing.model.CustomerImporter) key = 'corepos_card_number' supported_fields = [ 'corepos_card_number', + 'corepos_account_id', 'number', 'name', # 'address_street', @@ -171,6 +172,7 @@ class CustomerImporter(FromCOREPOSAPI, corepos_importing.model.CustomerImporter) return { 'corepos_card_number': card_number, + 'corepos_account_id': int(customer['customerAccountID']), 'number': card_number, 'name': normalize_full_name(customer['firstName'], customer['lastName']), @@ -183,7 +185,7 @@ class CustomerImporter(FromCOREPOSAPI, corepos_importing.model.CustomerImporter) } -class CustomerShopperImporter(FromCOREPOSAPI, importing.model.CustomerShopperImporter): +class CustomerShopperImporter(FromCOREPOSAPI, corepos_importing.model.CustomerShopperImporter): """ Importer for customer shopper data from CORE POS API. """ @@ -191,6 +193,7 @@ class CustomerShopperImporter(FromCOREPOSAPI, importing.model.CustomerShopperImp supported_fields = [ 'customer_uuid', 'shopper_number', + 'corepos_customer_id', 'first_name', 'last_name', 'display_name', @@ -281,6 +284,7 @@ class CustomerShopperImporter(FromCOREPOSAPI, importing.model.CustomerShopperImp data = { 'customer_uuid': customer.uuid, 'shopper_number': shopper['shopper_number'], + 'corepos_customer_id': int(shopper['customerID']), 'first_name': shopper['firstName'], 'last_name': shopper['lastName'], diff --git a/rattail_corepos/importing/model.py b/rattail_corepos/importing/model.py index 0529677..36830af 100644 --- a/rattail_corepos/importing/model.py +++ b/rattail_corepos/importing/model.py @@ -64,6 +64,15 @@ class CustomerImporter(importing.model.CustomerImporter): } +class CustomerShopperImporter(importing.model.CustomerShopperImporter): + + extensions = { + '_corepos': [ + 'corepos_customer_id', + ], + } + + class MemberImporter(importing.model.MemberImporter): extensions = {