class CitizenList(Resource): citizen_schema = CitizenSchema() citizens_schema = CitizenSchema(many=True) @oidc.accept_token(require_token=True) def get(self): try: csr = CSR.query.filter_by(username=g.oidc_token_info['username']. split("idir/")[-1]).first() active_state = CitizenState.query.filter_by( cs_state_name="Active").first() citizens = Citizen.query.filter_by(office_id=csr.office_id, cs_id=active_state.cs_id) \ .join(Citizen.service_reqs).all() result = self.citizens_schema.dump(citizens) return {'citizens': result.data, 'errors': result.errors}, 200 except exc.SQLAlchemyError as e: print(e) return {'message': 'API is down'}, 500 @oidc.accept_token(require_token=True) @api_call_with_retry def post(self): json_data = request.get_json() csr = CSR.query.filter_by( username=g.oidc_token_info['username'].split("idir/")[-1]).first() try: citizen = self.citizen_schema.load(json_data).data citizen.office_id = csr.office_id citizen.start_time = datetime.now() except ValidationError as err: print(err) return {"message": err.messages}, 422 citizen_state = CitizenState.query.filter_by( cs_state_name="Active").first() citizen.cs_id = citizen_state.cs_id db.session.add(citizen) db.session.commit() SnowPlow.add_citizen(citizen, csr) # socketio.emit('update_customer_list', {}) result = self.citizen_schema.dump(citizen) return {'citizen': result.data, 'errors': result.errors}, 201
class CsrSelf(Resource): csr_schema = CSRSchema() citizen_schema = CitizenSchema(many=True) @oidc.accept_token(require_token=True) def get(self): try: csr = CSR.query.filter_by(username=g.oidc_token_info['username']. split("idir/")[-1]).first() active_sr_state = SRState.query.filter_by(sr_code='Active').first() active_citizens = Citizen.query \ .join(Citizen.service_reqs) \ .filter_by(sr_state_id=active_sr_state.sr_state_id) \ .join(ServiceReq.periods) \ .filter_by(csr_id=csr.csr_id) \ .filter(Period.time_end.is_(None)) result = self.csr_schema.dump(csr) active_citizens = self.citizen_schema.dump(active_citizens) return { 'csr': result.data, 'active_citizens': active_citizens.data, 'errors': result.errors } except exc.SQLAlchemyError as e: print(e) return {'message': 'API is down'}, 500
class CitizenPlaceOnHold(Resource): citizen_schema = CitizenSchema() @oidc.accept_token(require_token=True) @api_call_with_retry def post(self, id): csr = CSR.query.filter_by( username=g.oidc_token_info['username'].split("idir/")[-1]).first() citizen = Citizen.query.filter_by(citizen_id=id, office_id=csr.office_id).first() active_service_request = citizen.get_active_service_request() if active_service_request is None: return {"message": "Citizen has no active service requests"} active_service_request.place_on_hold(csr) pending_service_state = SRState.query.filter_by( sr_code='Active').first() active_service_request.sr_state_id = pending_service_state.sr_state_id db.session.add(citizen) db.session.commit() socketio.emit('update_customer_list', {}, room=csr.office_id) result = self.citizen_schema.dump(citizen) socketio.emit('update_active_citizen', result.data, room=csr.office_id) return {'citizen': result.data, 'errors': result.errors}, 200
class ServiceRequestActivate(Resource): citizen_schema = CitizenSchema() service_requests_schema = ServiceReqSchema(many=True) service_request_schema = ServiceReqSchema() @oidc.accept_token(require_token=True) @api_call_with_retry def post(self, id): csr = CSR.find_by_username(g.oidc_token_info['username']) service_request = ServiceReq.query.filter_by(sr_id=id) \ .join(ServiceReq.citizen, aliased=True) \ .filter_by(office_id=csr.office_id).first_or_404() active_service_state = SRState.get_state_by_name("Active") complete_service_state = SRState.get_state_by_name("Complete") # Find the currently active service_request and close it for req in service_request.citizen.service_reqs: if req.sr_state_id == active_service_state.sr_state_id: req.sr_state_id = complete_service_state.sr_state_id req.finish_service(csr, clear_comments=False) db.session.add(req) # Then set the requested service to active service_request.sr_state_id = active_service_state.sr_state_id period_state_being_served = PeriodState.get_state_by_name( "Being Served") new_period = Period(sr_id=service_request.sr_id, csr_id=csr.csr_id, reception_csr_ind=csr.receptionist_ind, ps_id=period_state_being_served.ps_id, time_start=datetime.now()) db.session.add(new_period) db.session.add(service_request) citizen_obj = Citizen.query.get(service_request.citizen_id) citizen_obj.service_count = citizen_obj.service_count + 1 db.session.commit() SnowPlow.choose_service(service_request, csr, "additionalservice") citizen_result = self.citizen_schema.dump(service_request.citizen) socketio.emit('update_active_citizen', citizen_result.data, room=csr.office_id) result = self.service_request_schema.dump(service_request) return {'service_request': result.data, 'errors': result.errors}, 200
class CitizenBeginService(Resource): citizen_schema = CitizenSchema() @oidc.accept_token(require_token=True) @api_call_with_retry def post(self, id): lock = FileLock("lock/begin_citizen.lock") with lock: csr = CSR.find_by_username(g.oidc_token_info['username']) citizen = Citizen.query.filter_by(citizen_id=id, office_id=csr.office_id).first() pending_service_state = SRState.get_state_by_name("Active") active_service_request = citizen.get_active_service_request() if active_service_request is None: return {"message": "Citizen has no active service requests"} try: # Get Snowplow call. active_period = active_service_request.get_active_period() snowplow_event = "beginservice" if active_period.ps.ps_name == "On hold": snowplow_event = "invitefromhold" if active_period.ps.ps_name == "Waiting": snowplow_event = "invitefromlist" active_service_request.begin_service(csr, snowplow_event) except TypeError: return {"message": "Citizen has already been invited"}, 400 active_service_request.sr_state_id = pending_service_state.sr_state_id db.session.add(citizen) db.session.commit() if snowplow_event != "beginservice": socketio.emit('update_customer_list', {}, room=csr.office_id) result = self.citizen_schema.dump(citizen) socketio.emit('update_active_citizen', result.data, room=csr.office_id) return {'citizen': result.data, 'errors': result.errors}, 200
class CitizenLeft(Resource): service_request_schema = ServiceReqSchema(many=True) citizen_schema = CitizenSchema() clear_comments_flag = (os.getenv("THEQ_CLEAR_COMMENTS_FLAG", "True")).upper() == "TRUE" @oidc.accept_token(require_token=True) @api_call_with_retry def post(self, id): csr = CSR.find_by_username(g.oidc_token_info['username']) citizen = Citizen.query.filter_by(citizen_id=id, office_id=csr.office_id).first() sr_state = SRState.get_state_by_name("Complete") for service_request in citizen.service_reqs: service_request.sr_state_id = sr_state.sr_state_id for p in service_request.periods: if p.time_end is None: p.time_end = datetime.now() citizen.cs = CitizenState.query.filter_by( cs_state_name='Left before receiving services').first() if self.clear_comments_flag: citizen.citizen_comments = None if citizen.start_time.date() != datetime.now().date(): citizen.accurate_time_ind = 0 db.session.add(citizen) db.session.commit() SnowPlow.snowplow_event(citizen.citizen_id, csr, "customerleft") socketio.emit('citizen_invited', {}, room='sb-%s' % csr.office.office_number) result = self.citizen_schema.dump(citizen) socketio.emit('update_active_citizen', result.data, room=csr.office_id) return {'citizen': result.data, 'errors': result.errors}, 200
class CitizenSpecificInvite(Resource): citizen_schema = CitizenSchema() @oidc.accept_token(require_token=True) @api_call_with_retry def post(self, id): lock = FileLock("lock/invite_citizen.lock") with lock: csr = CSR.query.filter_by(username=g.oidc_token_info['username']. split("idir/")[-1]).first() citizen = db.session.query(Citizen).with_lockmode( 'update').filter_by(citizen_id=id).first() active_service_state = SRState.query.filter_by( sr_code='Active').first() active_service_request = citizen.get_active_service_request() if active_service_request is None: return { "message": "Citizen has no active service requests" }, 400 try: active_service_request.invite(csr) except TypeError: return {"message": "Citizen has already been invited"}, 400 active_service_request.sr_state_id = active_service_state.sr_state_id db.session.add(citizen) db.session.commit() socketio.emit('update_customer_list', {}, room=csr.office_id) socketio.emit('citizen_invited', {}, room='sb-%s' % csr.office.office_number) result = self.citizen_schema.dump(citizen) socketio.emit('update_active_citizen', result.data, room=csr.office_id) return {'citizen': result.data, 'errors': result.errors}, 200
class CitizenDetail(Resource): citizen_schema = CitizenSchema() @oidc.accept_token(require_token=True) def get(self, id): try: csr = CSR.find_by_username(g.oidc_token_info['username']) citizen = Citizen.query.filter_by(citizen_id=id, office_id=csr.office_id).first() result = self.citizen_schema.dump(citizen) return {'citizen': result.data, 'errors': result.errors} except exc.SQLAlchemyError as e: print(e) return {'message': 'API is down'}, 500 @oidc.accept_token(require_token=True) @api_call_with_retry def put(self, id): json_data = request.get_json() if not json_data: return {'message': 'No input data received for updating citizen'}, 400 csr = CSR.find_by_username(g.oidc_token_info['username']) citizen = Citizen.query.filter_by(citizen_id=id, office_id=csr.office_id).first() try: citizen = self.citizen_schema.load(json_data, instance=citizen, partial=True).data except ValidationError as err: return {'message': err.messages}, 422 db.session.add(citizen) db.session.commit() result = self.citizen_schema.dump(citizen) socketio.emit('update_active_citizen', result.data, room=csr.office_id) return {'citizen': result.data, 'errors': result.errors}, 200
class CitizenLeft(Resource): service_request_schema = ServiceReqSchema(many=True) citizen_schema = CitizenSchema() @oidc.accept_token(require_token=True) @api_call_with_retry def post(self, id): csr = CSR.query.filter_by( username=g.oidc_token_info['username'].split("idir/")[-1]).first() citizen = Citizen.query.filter_by(citizen_id=id, office_id=csr.office_id).first() sr_state = SRState.query.filter_by(sr_code="Complete").first() # Save this service for the Snowplow call later. active_service_request = citizen.get_active_service_request() for service_request in citizen.service_reqs: service_request.sr_state_id = sr_state.sr_state_id for p in service_request.periods: if p.time_end is None: p.time_end = datetime.now() citizen.cs = CitizenState.query.filter_by( cs_state_name='Left before receiving services').first() citizen.citizen_comments = None db.session.add(citizen) db.session.commit() SnowPlow.snowplow_event(citizen.citizen_id, csr, "customerleft") socketio.emit('update_customer_list', {}, room=csr.office_id) socketio.emit('citizen_invited', {}, room='sb-%s' % csr.office.office_number) result = self.citizen_schema.dump(citizen) socketio.emit('update_active_citizen', result.data, room=csr.office_id) return {'citizen': result.data, 'errors': result.errors}, 200
class ServiceRequestsDetail(Resource): citizen_schema = CitizenSchema() service_requests_schema = ServiceReqSchema(many=True) service_request_schema = ServiceReqSchema() @oidc.accept_token(require_token=True) @api_call_with_retry def put(self, id): json_data = request.get_json() if not json_data: return { 'message': 'No input data received for updating citizen' }, 400 csr = CSR.query.filter_by( username=g.oidc_token_info['username'].split("idir/")[-1]).first() service_request = ServiceReq.query.filter_by(sr_id=id) \ .join(ServiceReq.citizen, aliased=True) \ .filter_by(office_id=csr.office_id).first_or_404() try: service_request = self.service_request_schema.load( json_data, instance=service_request, partial=True).data except ValidationError as err: return {'message': err.messages}, 422 db.session.add(service_request) db.session.commit() SnowPlow.choose_service(service_request, csr, "chooseservice") result = self.service_request_schema.dump(service_request) citizen_result = self.citizen_schema.dump(service_request.citizen) socketio.emit('update_active_citizen', citizen_result.data, room=csr.office_id) return {'service_request': result.data, 'errors': result.errors}, 200
class CitizenAddToQueue(Resource): citizen_schema = CitizenSchema() @oidc.accept_token(require_token=True) @api_call_with_retry def post(self, id): csr = CSR.query.filter_by( username=g.oidc_token_info['username'].split("idir/")[-1]).first() citizen = Citizen.query.filter_by(citizen_id=id, office_id=csr.office_id).first() active_service_request = citizen.get_active_service_request() if active_service_request is None: return {"message": "Citizen has no active service requests"} # Figure out what Snowplow call to make. snowplow_call = "returntoqueue" if ((len(citizen.service_reqs) == 1) and (len(active_service_request.periods) == 1)): snowplow_call = "addtoqueue" active_service_request.add_to_queue(csr, snowplow_call) pending_service_state = SRState.query.filter_by( sr_code='Pending').first() active_service_request.sr_state_id = pending_service_state.sr_state_id db.session.add(citizen) db.session.commit() socketio.emit('update_customer_list', {}, room=csr.office_id) socketio.emit('citizen_invited', {}, room='sb-%s' % csr.office.office_number) result = self.citizen_schema.dump(citizen) socketio.emit('update_active_citizen', result.data, room=csr.office_id) return {'citizen': result.data, 'errors': result.errors}, 200
class CitizenFinishService(Resource): citizen_schema = CitizenSchema() @oidc.accept_token(require_token=True) @api_call_with_retry def post(self, id): csr = CSR.find_by_username(g.oidc_token_info['username']) citizen = Citizen.query.filter_by(citizen_id=id, office_id=csr.office_id).first() active_service_request = citizen.get_active_service_request() if active_service_request is None: return {"message": "Citizen has no active service requests"} quantity = active_service_request.quantity active_service_request.finish_service(csr) citizen_state = CitizenState.query.filter_by( cs_state_name="Received Services").first() citizen.cs_id = citizen_state.cs_id pending_service_state = SRState.get_state_by_name("Complete") active_service_request.sr_state_id = pending_service_state.sr_state_id db.session.add(citizen) db.session.commit() SnowPlow.snowplow_event(citizen.citizen_id, csr, "finish", quantity=quantity) socketio.emit('citizen_invited', {}, room='sb-%s' % csr.office.office_number) result = self.citizen_schema.dump(citizen) socketio.emit('update_active_citizen', result.data, room=csr.office_id) return {'citizen': result.data, 'errors': result.errors}, 200
class ServiceRequestsList(Resource): citizen_schema = CitizenSchema() service_request_schema = ServiceReqSchema() @oidc.accept_token(require_token=True) @api_call_with_retry def post(self): json_data = request.get_json() if not json_data: return {"message": "No input data received for creating service request"}, 400 csr = CSR.find_by_username(g.oidc_token_info['username']) try: service_request = self.service_request_schema.load(json_data['service_request']).data except ValidationError as err: return {"message": err.messages}, 422 except KeyError as err: print (err) return {"message": str(err)} active_sr_state = SRState.get_state_by_name("Active") complete_sr_state = SRState.get_state_by_name("Complete") citizen_state = CitizenState.query.filter_by(cs_state_name="Active").first() citizen = Citizen.query.get(service_request.citizen_id) service = Service.query.get(service_request.service_id) if citizen is None: return {"message": "No matching citizen found for citizen_id"}, 400 if service is None: return {"message": "No matching service found for service_id"}, 400 # Find the currently active service_request and close it (if it exists) for req in citizen.service_reqs: if req.sr_state_id == active_sr_state.sr_state_id: req.sr_state_id = complete_sr_state.sr_state_id req.finish_service(csr, clear_comments=False) db.session.add(req) service_request.sr_state_id = active_sr_state.sr_state_id # Only add ticket creation period and ticket number if it's their first service_request if len(citizen.service_reqs) == 0: period_state_ticket_creation = PeriodState.get_state_by_name("Ticket Creation") ticket_create_period = Period( csr_id=csr.csr_id, reception_csr_ind=csr.receptionist_ind, ps_id=period_state_ticket_creation.ps_id, time_start=citizen.get_service_start_time(), time_end=datetime.now() ) service_request.periods.append(ticket_create_period) # Move start_time back 6 hours to account for DST and UTC offsets # It's only important that the number carries over _around_ midnight offset_start_time = citizen.start_time - timedelta(hours=6) service_count = ServiceReq.query \ .join(ServiceReq.citizen, aliased=True) \ .filter(Citizen.start_time >= offset_start_time.strftime("%Y-%m-%d")) \ .filter_by(office_id=csr.office_id) \ .join(ServiceReq.service, aliased=True) \ .filter_by(prefix=service.prefix) \ .count() citizen.ticket_number = service.prefix + str(service_count) else: period_state_being_served = PeriodState.get_state_by_name("Being Served") ticket_create_period = Period( csr_id=csr.csr_id, reception_csr_ind=csr.receptionist_ind, ps_id=period_state_being_served.ps_id, time_start=datetime.now() ) service_request.periods.append(ticket_create_period) citizen.cs_id = citizen_state.cs_id # See whether first service, or next service. if len(citizen.service_reqs) == 0: snowplow_event = "chooseservice" citizen.service_count = 1 else: snowplow_event = "additionalservice" citizen.service_count = citizen.service_count + 1 db.session.add(service_request) db.session.add(citizen) db.session.commit() SnowPlow.choose_service(service_request, csr, snowplow_event) citizen_result = self.citizen_schema.dump(citizen) socketio.emit('update_active_citizen', citizen_result.data, room=csr.office_id) result = self.service_request_schema.dump(service_request) return {'service_request': result.data, 'errors': result.errors}, 201
class CitizenGenericInvite(Resource): citizen_schema = CitizenSchema() citizens_schema = CitizenSchema(many=True) @oidc.accept_token(require_token=True) @api_call_with_retry def post(self): lock = FileLock("lock/invite_citizen.lock") with lock: csr = CSR.find_by_username(g.oidc_token_info['username']) active_citizen_state = CitizenState.query.filter_by( cs_state_name='Active').first() waiting_period_state = PeriodState.get_state_by_name("Waiting") citizen = None try: qt_xn_csr_ind = request.get_json().get('qt_xn_csr_ind') except AttributeError: qt_xn_csr_ind = csr.qt_xn_csr_ind if qt_xn_csr_ind: citizen = Citizen.query \ .filter_by(qt_xn_citizen_ind=1, cs_id=active_citizen_state.cs_id, office_id=csr.office_id) \ .join(Citizen.service_reqs) \ .join(ServiceReq.periods) \ .filter_by(ps_id=waiting_period_state.ps_id) \ .filter(Period.time_end.is_(None)) \ .order_by(Citizen.priority, Citizen.citizen_id) \ .first() else: citizen = Citizen.query \ .filter_by(qt_xn_citizen_ind=0, cs_id=active_citizen_state.cs_id, office_id=csr.office_id) \ .join(Citizen.service_reqs) \ .join(ServiceReq.periods) \ .filter_by(ps_id=waiting_period_state.ps_id) \ .filter(Period.time_end.is_(None)) \ .order_by(Citizen.priority, Citizen.citizen_id) \ .first() # Either no quick txn citizens for the quick txn csr, or vice versa if citizen is None: citizen = Citizen.query \ .filter_by(cs_id=active_citizen_state.cs_id, office_id=csr.office_id) \ .join(Citizen.service_reqs) \ .join(ServiceReq.periods) \ .filter_by(ps_id=waiting_period_state.ps_id) \ .filter(Period.time_end.is_(None)) \ .order_by(Citizen.priority, Citizen.citizen_id) \ .first() if citizen is None: return {"message": "There is no citizen to invite"}, 400 db.session.refresh(citizen) active_service_request = citizen.get_active_service_request() try: active_service_request.invite(csr, "invitecitizen") except TypeError: return { "message": "Error inviting citizen. Please try again." }, 400 active_service_state = SRState.get_state_by_name("Active") active_service_request.sr_state_id = active_service_state.sr_state_id db.session.add(citizen) db.session.commit() socketio.emit('update_customer_list', {}, room=csr.office_id) socketio.emit('citizen_invited', {}, room='sb-%s' % csr.office.office_number) result = self.citizen_schema.dump(citizen) socketio.emit('update_active_citizen', result.data, room=csr.office_id) return {'citizen': result.data, 'errors': result.errors}, 200
from app import app, db from flask import request from flask import jsonify from app.schemas import CitizenSchema, ImportSchema, ChangeCitizenSchema from app.models import Imports, Citizens from marshmallow import ValidationError from sqlalchemy import func import numpy as np from sqlalchemy.exc import IntegrityError import_schema = ImportSchema() citizen_schema = CitizenSchema() change_citizen_schema = ChangeCitizenSchema() @app.route('/imports', methods=['POST']) def imports(): try: content = request.get_json() # Валидация import_obj = import_schema.load(content) # Сохраняем import и получаем import_id new_import = Imports() db.session.add(new_import) db.session.flush() db.session.refresh(new_import) # Сохраняем каждого горожанина for c in import_obj['citizens']: citizen = Citizens(**c) citizen.import_id = new_import.id