rattail-corepos/rattail_corepos/datasync/corepos.py

207 lines
7.2 KiB
Python

# -*- coding: utf-8; -*-
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2020 Lance Edgar
#
# This file is part of Rattail.
#
# Rattail is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# Rattail. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
DataSync for CORE POS
"""
from corepos.db.office_op import Session as CoreSession, model as corepos
from rattail.db import model
from rattail.datasync import DataSyncWatcher, NewDataSyncImportConsumer
class CoreOfficeOpWatcher(DataSyncWatcher):
"""
DataSync watcher for the CORE ``office_op`` database.
"""
prunes_changes = True
def get_changes(self, lastrun):
session = CoreSession()
changes = session.query(corepos.Change).all()
session.expunge_all()
session.close()
if changes:
return [
(c.id,
model.DataSyncChange(
payload_type=c.object_type,
payload_key=c.object_key,
deletion=c.deleted))
for c in changes]
def prune_changes(self, keys):
deleted = 0
session = CoreSession()
for key in keys:
change = session.query(corepos.Change).get(key)
if change:
session.delete(change)
session.flush()
deleted += 1
session.commit()
session.close()
return deleted
class COREPOSProductWatcher(DataSyncWatcher):
"""
DataSync watcher for the CORE POS database.
"""
def get_changes(self, lastrun):
if not lastrun:
return
changes = []
session = CoreSession()
lastrun = self.localize_lastrun(session, lastrun)
# Department
departments = session.query(corepos.Department)\
.filter(corepos.Department.modified >= lastrun)\
.all()
if departments:
changes.extend([
(None,
model.DataSyncChange(
payload_type='Department',
payload_key=str(dept.number)))
for dept in departments])
# TODO: subdepartment table doesn't have a modified flag?
# # Subdepartment
# subdepartments = session.query(corepos.Subdepartment)\
# .filter(corepos.Subdepartment.modified >= lastrun)\
# .all()
# if subdepartments:
# changes.extend([
# (None,
# model.DataSyncChange(
# payload_type='Subdepartment',
# payload_key=six.text_type(subdept.subdept_no)))
# for subdept in subdepartments])
# TODO: vendor table doesn't have a modified flag?
# # Vendor
# vendors = session.query(corepos.Vendor)\
# .filter(corepos.Vendor.modified >= lastrun)\
# .all()
# if vendors:
# changes.extend([
# (None,
# model.DataSyncChange(
# payload_type='Vendor',
# payload_key=six.text_type(vendor.vendorID)))
# for vendor in vendors])
# Product
products = session.query(corepos.Product)\
.filter(corepos.Product.modified >= lastrun)\
.all()
if products:
changes.extend([
(None,
model.DataSyncChange(
payload_type='Product',
payload_key=product.upc))
for product in products
if product.upc])
session.close()
return changes
class FromRattailToCore(NewDataSyncImportConsumer):
"""
Rattail -> CORE POS datasync consumer
"""
handler_spec = 'rattail_corepos.corepos.importing.rattail:FromRattailToCore'
def process_changes(self, session, changes):
"""
Process all the given changes, coming from Rattail.
"""
# TODO: this probably doesn't accomplish anything here?
if self.runas_username:
session.set_continuum_user(self.runas_username)
# update all importers with current session
for importer in self.importers.values():
importer.host_session = session
# also establish the API client for each!
importer.establish_api()
# sync all Department changes
types = [
'Department',
]
for change in [c for c in changes if c.payload_type in types]:
if change.payload_type == 'Department' and change.deletion:
# TODO: we have no way (yet) to delete a CORE department via API
# # just do default logic for this one
# self.invoke_importer(session, change)
pass
else: # we consider this an "add/update"
department = self.get_department(session, change)
if department:
self.process_change(session, self.importers['Department'],
host_object=department)
# sync all Vendor changes
types = [
'Vendor',
'VendorPhoneNumber',
'VendorEmailAddress',
]
for change in [c for c in changes if c.payload_type in types]:
if change.payload_type == 'Vendor' and change.deletion:
# # just do default logic for this one
# self.invoke_importer(session, change)
# TODO: we have no way to delete a CORE vendor via API, right?
pass
else: # we consider this an "add/update"
vendor = self.get_vendor(session, change)
if vendor:
self.process_change(session, self.importers['Vendor'],
host_object=vendor)
def get_department(self, session, change):
if change.payload_type == 'Department':
return session.query(model.Department).get(change.payload_key)
def get_vendor(self, session, change):
if change.payload_type == 'Vendor':
return session.query(model.Vendor).get(change.payload_key)
if change.payload_type == 'VendorPhoneNumber':
phone = session.query(model.VendorPhoneNumber).get(change.payload_key)
if phone:
return phone.vendor
if change.payload_type == 'VendorEmailAddress':
email = session.query(model.VendorEmailAddress).get(change.payload_key)
if email:
return email.vendor