Add customer, member importers from CORE DB
API is just not cutting it, need more flexibility
This commit is contained in:
parent
124a510c17
commit
d08c475223
|
@ -0,0 +1,38 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
"""add core_member.corepos_card_number
|
||||
|
||||
Revision ID: 15bf65f68c52
|
||||
Revises: 673ff7088d35
|
||||
Create Date: 2023-10-12 07:39:34.608105
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '15bf65f68c52'
|
||||
down_revision = '673ff7088d35'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import rattail.db.types
|
||||
|
||||
|
||||
|
||||
def upgrade():
|
||||
|
||||
# corepos_member
|
||||
op.alter_column('corepos_member', 'corepos_account_id',
|
||||
existing_type=sa.INTEGER(),
|
||||
nullable=True)
|
||||
op.add_column('corepos_member', sa.Column('corepos_card_number', sa.Integer(), nullable=True))
|
||||
op.add_column('corepos_member_version', sa.Column('corepos_card_number', sa.Integer(), autoincrement=False, nullable=True))
|
||||
|
||||
def downgrade():
|
||||
|
||||
# corepos_member
|
||||
op.drop_column('corepos_member_version', 'corepos_card_number')
|
||||
op.drop_column('corepos_member', 'corepos_card_number')
|
||||
op.alter_column('corepos_member', 'corepos_account_id',
|
||||
existing_type=sa.INTEGER(),
|
||||
nullable=False)
|
|
@ -205,14 +205,20 @@ class CoreMember(model.Base):
|
|||
Reference to the CORE-POS extension record for this member.
|
||||
"""))
|
||||
|
||||
corepos_account_id = sa.Column(sa.Integer(), nullable=False, doc="""
|
||||
corepos_account_id = sa.Column(sa.Integer(), nullable=True, doc="""
|
||||
``Customers.customerAccountID`` value for this member, within CORE-POS.
|
||||
""")
|
||||
|
||||
corepos_card_number = sa.Column(sa.Integer(), nullable=True, doc="""
|
||||
``meminfo.card_no`` / ``CustomerAccounts.cardNo`` value for this
|
||||
member, within CORE-POS.
|
||||
""")
|
||||
|
||||
def __str__(self):
|
||||
return str(self.member)
|
||||
|
||||
CoreMember.make_proxy(model.Member, '_corepos', 'corepos_account_id')
|
||||
CoreMember.make_proxy(model.Member, '_corepos', 'corepos_card_number')
|
||||
|
||||
|
||||
class CoreMemberEquityPayment(model.Base):
|
||||
|
|
|
@ -144,6 +144,8 @@ class CustomerImporter(FromCOREPOSAPI, corepos_importing.model.CustomerImporter)
|
|||
'corepos_account_id',
|
||||
'number',
|
||||
'name',
|
||||
# 'account_holder_first_name',
|
||||
# 'account_holder_last_name',
|
||||
'address_street',
|
||||
'address_street2',
|
||||
'address_city',
|
||||
|
@ -182,6 +184,8 @@ class CustomerImporter(FromCOREPOSAPI, corepos_importing.model.CustomerImporter)
|
|||
'name': normalize_full_name(customer['firstName'],
|
||||
customer['lastName']),
|
||||
|
||||
# 'account_holder_first_name': customer['firstName'],
|
||||
# 'account_holder_last_name': customer['lastName'],
|
||||
'address_street': member['addressFirstLine'] or None,
|
||||
'address_street2': member['addressSecondLine'] or None,
|
||||
'address_city': member['city'] or None,
|
||||
|
@ -783,10 +787,13 @@ class MemberImporter(FromCOREPOSAPI, corepos_importing.model.MemberImporter):
|
|||
"""
|
||||
Importer for member data from CORE POS API.
|
||||
"""
|
||||
# TODO use this key instead
|
||||
#key = 'corepos_card_number'
|
||||
key = 'number'
|
||||
supported_fields = [
|
||||
'number',
|
||||
'corepos_account_id',
|
||||
'corepos_card_number',
|
||||
'customer_uuid',
|
||||
'person_first_name',
|
||||
'person_last_name',
|
||||
|
@ -857,6 +864,8 @@ class MemberImporter(FromCOREPOSAPI, corepos_importing.model.MemberImporter):
|
|||
joined = datetime.datetime.strptime(member['startDate'],
|
||||
'%Y-%m-%d %H:%M:%S')
|
||||
joined = joined.date()
|
||||
if joined == datetime.date(1900, 1, 1):
|
||||
joined = None
|
||||
|
||||
withdrew = None
|
||||
if (member['endDate']
|
||||
|
@ -865,19 +874,20 @@ class MemberImporter(FromCOREPOSAPI, corepos_importing.model.MemberImporter):
|
|||
withdrew = datetime.datetime.strptime(member['endDate'],
|
||||
'%Y-%m-%d %H:%M:%S')
|
||||
withdrew = withdrew.date()
|
||||
if withdrew == datetime.date(1900, 1, 1):
|
||||
withdrew = None
|
||||
|
||||
typeno = int(member['customerTypeID']) or None
|
||||
if typeno:
|
||||
memtype = self.get_membership_type_by_number(typeno)
|
||||
if not memtype:
|
||||
logger = log.warning if self.get_warn_for_unknown_membership_type() else log.debug
|
||||
logger("unknown customerTypeID (membership_type_number) %s for: %s",
|
||||
member['customerTypeID'], member)
|
||||
typeno = None
|
||||
typeno = int(member['customerTypeID'])
|
||||
memtype = self.get_membership_type_by_number(typeno)
|
||||
if not memtype:
|
||||
log.warning("unknown customerTypeID (membership_type_number) %s for: %s",
|
||||
member['customerTypeID'], member)
|
||||
typeno = None
|
||||
|
||||
data = {
|
||||
'number': card_number,
|
||||
'corepos_account_id': int(member['customerAccountID']),
|
||||
'corepos_card_number': card_number,
|
||||
'customer_uuid': customer.uuid if customer else None,
|
||||
'person_first_name': None,
|
||||
'person_last_name': None,
|
||||
|
|
|
@ -24,10 +24,12 @@
|
|||
CORE POS (DB) -> Rattail data importing
|
||||
"""
|
||||
|
||||
import datetime
|
||||
import decimal
|
||||
import logging
|
||||
from collections import OrderedDict
|
||||
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import orm
|
||||
|
||||
from corepos.db.office_op import model as corepos, Session as CoreSession
|
||||
|
@ -67,6 +69,8 @@ class FromCOREPOSToRattail(importing.FromSQLAlchemyHandler, importing.ToRattailH
|
|||
def get_importers(self):
|
||||
importers = OrderedDict()
|
||||
importers['Employee'] = EmployeeImporter
|
||||
importers['Customer'] = CustomerImporter
|
||||
importers['Member'] = MemberImporter
|
||||
importers['Tax'] = TaxImporter
|
||||
importers['Tender'] = TenderImporter
|
||||
importers['Vendor'] = VendorImporter
|
||||
|
@ -90,6 +94,25 @@ class FromCOREPOS(importing.FromSQLAlchemy):
|
|||
Base class for all CORE POS data importers.
|
||||
"""
|
||||
|
||||
def setup(self):
|
||||
super().setup()
|
||||
self.ignore_new_members = self.should_ignore_new_members()
|
||||
|
||||
def should_ignore_new_members(self):
|
||||
if hasattr(self, 'ignore_new_members'):
|
||||
return self.ignore_new_members
|
||||
|
||||
return self.config.getbool('rattail_corepos',
|
||||
'importing_ignore_new_members',
|
||||
default=False)
|
||||
|
||||
def is_new_member(self, member):
|
||||
if member.customers:
|
||||
customer = member.customers[0]
|
||||
if customer.last_name == 'NEW MEMBER'and not customer.first_name:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class EmployeeImporter(FromCOREPOS, corepos_importing.model.EmployeeImporter):
|
||||
"""
|
||||
|
@ -115,6 +138,195 @@ class EmployeeImporter(FromCOREPOS, corepos_importing.model.EmployeeImporter):
|
|||
}
|
||||
|
||||
|
||||
class CustomerImporter(FromCOREPOS, corepos_importing.model.CustomerImporter):
|
||||
"""
|
||||
Importer for customer data from CORE POS.
|
||||
"""
|
||||
host_model_class = corepos.MemberInfo
|
||||
key = 'corepos_card_number'
|
||||
supported_fields = [
|
||||
'corepos_card_number',
|
||||
'number',
|
||||
'name',
|
||||
'account_holder_uuid',
|
||||
'account_holder_first_name',
|
||||
'account_holder_last_name',
|
||||
'email_address',
|
||||
'phone_number',
|
||||
'address_street',
|
||||
'address_street2',
|
||||
'address_city',
|
||||
'address_state',
|
||||
'address_zipcode',
|
||||
]
|
||||
|
||||
def setup(self):
|
||||
super().setup()
|
||||
model = self.model
|
||||
|
||||
query = self.session.query(model.Person)\
|
||||
.outerjoin(model.Customer,
|
||||
model.Customer.account_holder_uuid == model.Person.uuid)\
|
||||
.outerjoin(model.CoreCustomer)\
|
||||
.outerjoin(model.Member,
|
||||
model.Member.person_uuid == model.Person.uuid)\
|
||||
.outerjoin(model.CoreMember)\
|
||||
.filter(sa.or_(
|
||||
model.CoreCustomer.corepos_card_number != None,
|
||||
model.CoreMember.corepos_card_number != None))\
|
||||
.options(orm.joinedload(model.Person.customer_accounts)\
|
||||
.joinedload(model.Customer._corepos))
|
||||
def card_number(person, normal):
|
||||
customer = self.app.get_customer(person)
|
||||
if customer and customer.corepos_card_number:
|
||||
return customer.corepos_card_number
|
||||
member = self.app.get_member(person)
|
||||
if member and member.corepos_card_number:
|
||||
return member.corepos_card_number
|
||||
self.people_by_card_number = self.cache_model(model.Person, query=query,
|
||||
key=card_number)
|
||||
|
||||
def get_person(self, member):
|
||||
|
||||
if hasattr(self, 'people_by_card_number'):
|
||||
return self.people_by_card_number.get(member.card_number)
|
||||
|
||||
model = self.model
|
||||
|
||||
try:
|
||||
return self.session.query(model.Person)\
|
||||
.join(model.Customer,
|
||||
model.Customer.account_holder_uuid == model.Person.uuid)\
|
||||
.join(model.CoreCustomer)\
|
||||
.filter(model.CoreCustomer.corepos_card_number == member.card_number)\
|
||||
.one()
|
||||
except orm.exc.NoResultFound:
|
||||
pass
|
||||
|
||||
try:
|
||||
return self.session.query(model.Person)\
|
||||
.join(model.Member,
|
||||
model.Member.person_uuid == model.Person.uuid)\
|
||||
.join(model.CoreMember)\
|
||||
.filter(model.CoreMember.corepos_card_number == member.card_number)\
|
||||
.one()
|
||||
except orm.exc.NoResultFound:
|
||||
pass
|
||||
|
||||
def normalize_host_object(self, member):
|
||||
card_number = member.card_number
|
||||
|
||||
# maybe ignore NEW MEMBER accounts
|
||||
if self.should_ignore_new_members():
|
||||
if self.is_new_member(member):
|
||||
return
|
||||
|
||||
contact = member
|
||||
if member.customers:
|
||||
contact = member.customers[0]
|
||||
|
||||
person = self.get_person(member)
|
||||
|
||||
street = (member.street or '').split('\n')
|
||||
|
||||
return {
|
||||
'corepos_card_number': card_number,
|
||||
'number': card_number,
|
||||
'name': normalize_full_name(contact.first_name, contact.last_name),
|
||||
'account_holder_uuid': person.uuid if person else None,
|
||||
'account_holder_first_name': contact.first_name,
|
||||
'account_holder_last_name': contact.last_name,
|
||||
'email_address': (member.email or '').strip() or None,
|
||||
'phone_number': self.app.format_phone_number((member.phone or '').strip() or None),
|
||||
'address_street': street[0] or None,
|
||||
'address_street2': (street[1] or None) if len(street) > 1 else None,
|
||||
'address_city': member.city or None,
|
||||
'address_state': member.state or None,
|
||||
'address_zipcode': member.zip or None,
|
||||
}
|
||||
|
||||
|
||||
class MemberImporter(FromCOREPOS, corepos_importing.model.MemberImporter):
|
||||
"""
|
||||
Importer for member data from CORE POS.
|
||||
"""
|
||||
host_model_class = corepos.MemberInfo
|
||||
# TODO use this key instead
|
||||
#key = 'corepos_card_number'
|
||||
key = 'number'
|
||||
supported_fields = [
|
||||
'number',
|
||||
'corepos_card_number',
|
||||
'customer_uuid',
|
||||
'person_first_name',
|
||||
'person_last_name',
|
||||
'membership_type_number',
|
||||
'joined',
|
||||
'withdrew',
|
||||
'active',
|
||||
]
|
||||
|
||||
def setup(self):
|
||||
super().setup()
|
||||
model = self.model
|
||||
|
||||
self.customers_by_number = self.app.cache_model(self.session,
|
||||
model.Customer,
|
||||
key='number')
|
||||
|
||||
def get_customer_by_number(self, number):
|
||||
if hasattr(self, 'customers_by_number'):
|
||||
return self.customers_by_number.get(number)
|
||||
|
||||
model = self.model
|
||||
try:
|
||||
return self.session.query(model.Customer)\
|
||||
.filter(model.Customer.number == number)\
|
||||
.one()
|
||||
except orm.exc.NoResultFound:
|
||||
pass
|
||||
|
||||
def normalize_host_object(self, core_member):
|
||||
|
||||
# maybe ignore NEW MEMBER accounts
|
||||
if self.should_ignore_new_members():
|
||||
if self.is_new_member(core_member):
|
||||
return
|
||||
|
||||
core_customer = core_member.customers[0] if core_member.customers else None
|
||||
core_contact = core_customer or core_member
|
||||
|
||||
card_number = core_member.card_number
|
||||
customer = self.get_customer_by_number(card_number)
|
||||
|
||||
typeno = None
|
||||
if core_customer and core_customer.member_type:
|
||||
typeno = core_customer.member_type.id
|
||||
|
||||
joined = None
|
||||
withdrew = None
|
||||
if core_member.dates:
|
||||
dates = core_member.dates
|
||||
joined = dates.start_date.date() if dates.start_date else None
|
||||
withdrew = dates.end_date.date() if dates.end_date else None
|
||||
if joined and joined == datetime.date(1900, 1, 1):
|
||||
joined = None
|
||||
if withdrew and withdrew == datetime.date(1900, 1, 1):
|
||||
withdrew = None
|
||||
|
||||
return {
|
||||
'number': card_number,
|
||||
'corepos_card_number': card_number,
|
||||
'customer_uuid': customer.uuid if customer else None,
|
||||
'person_first_name': core_contact.first_name,
|
||||
'person_last_name': core_contact.last_name,
|
||||
'membership_type_number': typeno,
|
||||
'joined': joined,
|
||||
'withdrew': withdrew,
|
||||
'active': not bool(withdrew),
|
||||
}
|
||||
|
||||
|
||||
class TaxImporter(FromCOREPOS, corepos_importing.model.TaxImporter):
|
||||
"""
|
||||
Importer for tax data from CORE POS.
|
||||
|
|
|
@ -87,6 +87,7 @@ class MemberImporter(importing.model.MemberImporter):
|
|||
extensions = {
|
||||
'_corepos': [
|
||||
'corepos_account_id',
|
||||
'corepos_card_number',
|
||||
],
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue