class Flight(ComplexModel): __namespace__ = 'testing' Index = Integer(min_occurs=0, max_occurs=1, nillable=True) flightNumber = Unicode(min_occurs=0, max_occurs=1, nillable=True) airline = Unicode(min_occurs=0, max_occurs=1, nillable=True) airlineIATA = Unicode(min_occurs=0, max_occurs=1, nillable=True) flightNumber = Unicode(min_occurs=0, max_occurs=1, nillable=True) nChild = Integer(min_occurs=0, max_occurs=1, nillable=True) nInfant = Integer(min_occurs=0, max_occurs=1, nillable=True) arrivalDateTime = DateTime(min_occurs=0, max_occurs=1, nillable=True) from_ = Unicode(min_occurs=0, max_occurs=1, nillable=False) to = Unicode(min_occurs=0, max_occurs=1, nillable=False) departureDatetime = DateTime(min_occurs=0, max_occurs=1, nillable=False) nAdult = Integer(min_occurs=0, max_occurs=1, nillable=False) AV = Array(AV.customize(nillable=True)) LConnections = Array(Connection.customize(nillable=True)) LFares = Array(Fare.customize(nillable=True)) validReturns = Array(Unicode(min_occurs=0, max_occurs=1, nillable=False)) type = Unicode(min_occurs=0, max_occurs=1, nillable=False) return_ = Boolean(min_occurs=0, max_occurs=1, nillable=False) schedule = Unicode(min_occurs=0, max_occurs=1, nillable=False) range = Unicode(min_occurs=0, max_occurs=1, nillable=False) info = Unicode(min_occurs=0, max_occurs=1, nillable=False)
def test_datetime_format(self): n = datetime.datetime.now().replace(microsecond=0) format = "%Y %m %d %H %M %S" element = etree.Element('test') XmlDocument().to_parent_element(DateTime(format=format), n, ns_test, element) element = element[0] assert element.text == datetime.datetime.strftime(n, format) dt = XmlDocument().from_element(DateTime(format=format), element) assert n == dt
class ClosestTicket(ComplexModel): __namespace__ = SOAP_NAMESPACE timeslotStart = DateTime(doc=u'Начало приёма у врача по талончику') timeslotEnd = DateTime(doc=u'Окончание приёма у врача по талончику') office = Unicode(doc=u'Кабинет приёма') doctor_id = Integer(doc=u'ID врача') def __init__(self): super(ClosestTicket, self).__init__(doc=u'Данные о ближайшем талончике')
def test_datetime_fixed_format(self): # Soap should ignore formats n = datetime.datetime.now().replace(microsecond=0) format = "%Y %m %d %H %M %S" element = etree.Element('test') Soap11().to_parent_element(DateTime(format=format), n, 'some_namespace', element) assert element[0].text == n.isoformat() dt = Soap11().from_element(DateTime(format=format), element[0]) assert n == dt
def test_datetime_serialize_as(self): i = 1234567890123456 v = datetime.datetime.fromtimestamp(i / 1e6) assert ProtocolBase().to_string(DateTime(serialize_as='sec'), v) == i // 1e6 assert ProtocolBase().to_string(DateTime(serialize_as='sec_float'), v) == i / 1e6 assert ProtocolBase().to_string(DateTime(serialize_as='msec'), v) == i // 1e3 assert ProtocolBase().to_string(DateTime(serialize_as='msec_float'), v) == i / 1e3 assert ProtocolBase().to_string(DateTime(serialize_as='usec'), v) == i
class InteropPrimitive(ServiceBase): @srpc(AnyXml, _returns=AnyXml) def echo_any(xml): return xml @srpc(AnyDict, _returns=AnyDict) def echo_any_as_dict(xml_as_dict): return xml_as_dict @srpc(Integer, _returns=Integer) def echo_integer(i): return i @srpc(String, _returns=String) def echo_string(s): return s @srpc(DateTime, _returns=DateTime) def echo_datetime(dt): return dt @srpc(DateTime(format='ignored'), _returns=DateTime) def echo_datetime_with_invalid_format(dt): return dt @srpc(Date, _returns=Date) def echo_date(d): return d @srpc(Date(format='ignored'), _returns=Date) def echo_date_with_invalid_format(d): return d @srpc(Time, _returns=Time) def echo_time(t): return t @srpc(Time(format='ignored'), _returns=Time) def echo_time_with_invalid_format(t): return t @srpc(Float, _returns=Float) def echo_float(f): return f @srpc(Double, _returns=Double) def echo_double(f): return f @srpc(Boolean, _returns=Boolean) def echo_boolean(b): return b @srpc(DaysOfWeekEnum, _returns=DaysOfWeekEnum) def echo_enum(day): return day @srpc(Duration, _returns=Duration) def echo_duration(dur): return dur
class Session(ComplexModel): __namespace__ = SOAP_NAMESPACE sessionStart = DateTime(doc=u'Начало смены') sessionEnd = DateTime(doc=u'Окончание смены') sessionType = SessionType() timeslots = Timeslot.customize( max_occurs='unbounded', doc=u'Информация об отдельных элементах расписания (тайм-слотах)') comments = Unicode( doc=u'Дополнительная информация о месте приёма или о замещениях') def __init__(self): super( Session, self).__init__(doc=u'Группа интервалов (смена) в расписании врача')
class MessageType(SmevModel): Sender = OrgExternalType.customize(type_name="Sender", min_occurs=1, max_occurs=1) Recipient = OrgExternalType.customize(type_name="Recipient", min_occurs=1, max_occurs=1) Originator = OrgExternalType.customize(type_name="Originator", min_occurs=0, max_occurs=1) ServiceName = Unicode(type_name="ServiceName", min_occurs=0, max_occurs=1) Service = ServiceType.customize(type_name="Service", max_occurs=1) TypeCode = Unicode(type_name="TypeCode", values=["GSRV", "GFNC", "OTHR"], min_occurs=1, max_occurs=1) Status = Unicode(type_name="Status", values=["REQUEST", "RESPONSE"], min_occurs=1, max_occurs=1) Date = DateTime(type_name="Date", min_occurs=1, max_occurs=1) ExchangeType = Integer(type_name="ExchangeType", max_occurs=1) RequestIdRef = Unicode(type_name="RequestIdRef", max_occurs=1) OriginRequestIdRef = Unicode(type_name="OriginRequestIdRef", max_occurs=1) ServiceCode = Unicode(type_name="ServiceCode", max_occurs=1) CaseNumber = Unicode(type_name="CaseNumber", max_occurs=1) SubMessages = SubMessages(type_name="SubMessages", max_occurs=1) TestMsg = Unicode(type_name="TestMsg", max_occurs=1)
class SomeService(Service): @srpc(DateTime, _returns=DateTime(ge=datetime(2010,1,1,tzinfo=pytz.utc))) def some_call(p): print(p) print(type(p)) assert type(p) == datetime assert p.isoformat() == d return p
class SisMsg(ComplexModel): """Container with metadata for Jiva integration messages carried in the MQ payload. """ data_source = String(nillable=False, min_occurs=1, max_occurs=1, max_len=50) direction = String(nillable=False, min_occurs=1, max_occurs=1, max_len=50) interface_name = String(nillable=False, min_occurs=1, max_occurs=1, max_len=50) crt_dt = DateTime(nillable=False)
class SomeService(Service): @srpc(DateTime, _returns=DateTime(timezone=False)) def some_call(p): print(p) print(type(p)) assert type(p) == datetime assert p.replace(tzinfo=None).isoformat() == d return p
class NonNillableClass(ComplexModel): __namespace__ = "hunk.sunk" nillable = False min_occurs = 1 dt = DateTime(min_occurs=1, nillable=False) i = Integer(nillable=False) s = String(min_len=1, nillable=False)
def test_datetime_deserialize(self): i = 1234567890123456 v = datetime.datetime.fromtimestamp(i / 1e6) assert ProtocolBase().from_string( DateTime(serialize_as='sec'), i//1e6) == \ datetime.datetime.fromtimestamp(i//1e6) assert ProtocolBase().from_string( DateTime(serialize_as='sec_float'), i/1e6) == v assert ProtocolBase().from_string( DateTime(serialize_as='msec'), i//1e3) == \ datetime.datetime.fromtimestamp(i/1e3//1000) assert ProtocolBase().from_string( DateTime(serialize_as='msec_float'), i/1e3) == v assert ProtocolBase().from_string( DateTime(serialize_as='usec'), i) == v
class Mandatory(object): """ This is spyne.model.primitive.Mandatory, but without min_length=1 for the Unicode model. """ Unicode = Unicode(type_name='mandatory_unicode', min_occurs=1, nillable=False) Integer = Integer(type_name='mandatory_integer', min_occurs=1, nillable=False) Boolean = Boolean(type_name='mandatory_boolean', min_occurs=1, nillable=False) DateTime = DateTime(type_name='mandatory_date_time', min_occurs=1, nillable=False) ByteArray = ByteArray(type_name='mandatory_byte_array', min_occurs=1, nillable=False)
class Connection(ComplexModel): Index = Integer(min_occurs=0, max_occurs=1, nillable=True) flightNumber = Unicode(min_occurs=0, max_occurs=1, nillable=True) airline = Unicode(min_occurs=0, max_occurs=1, nillable=True) airlineIATA = Unicode(min_occurs=0, max_occurs=1, nillable=True) flightNumber = Unicode(min_occurs=0, max_occurs=1, nillable=True) from_ = Unicode(min_occurs=0, max_occurs=1, nillable=True) fromAirport = Unicode(min_occurs=0, max_occurs=1, nillable=True) fromAirportIATA = Unicode(min_occurs=0, max_occurs=1, nillable=True) to = Unicode(min_occurs=0, max_occurs=1, nillable=False) toAirport = Unicode(min_occurs=0, max_occurs=1, nillable=False) toAirportIATA = Unicode(min_occurs=0, max_occurs=1, nillable=False) arrivalDateTime = DateTime(min_occurs=0, max_occurs=1, nillable=True) departureDatetime = DateTime(min_occurs=0, max_occurs=1, nillable=False) AV = Array(AV.customize(nillable=True)) map = Unicode(min_occurs=0, max_occurs=1, nillable=False)
def test_datetime_timezone(self): import pytz n = datetime.datetime.now(pytz.timezone('EST')) element = etree.Element('test') XmlDocument().to_parent_element(DateTime(as_time_zone=pytz.utc), n, ns_test, element) element = element[0] c = n.astimezone(pytz.utc).replace(tzinfo=None) self.assertEquals(element.text, c.isoformat()) dt = XmlDocument().from_element(DateTime, element) self.assertEquals(c, dt)
class GetClosestTicketsRequest(ComplexModel): __namespace__ = SOAP_NAMESPACE hospitalUid = String(doc=u'Уникальный идентификатор ЛПУ в БД ИС') doctors = Integer(min_occurs=1, max_occurs='unbounded', nillable=False, doc=u'Список идентификаторов врачей') start = DateTime() def __init__(self): super(GetClosestTicketsRequest, self).__init__( doc=u'Данные запроса на получение ближайших талончиков по врачам')
class SoapProject (ComplexModel): __namespace__ = 'soap' builddir = Unicode() name = Unicode() version = Unicode() status = Unicode() edit = DateTime() def __init__(self, prj): self.builddir = prj.builddir self.name = prj.name self.version = prj.version self.status = prj.status self.edit = prj.edit
def test_datetime_timezone(self): import pytz n = datetime.datetime.now(pytz.timezone('EST')) element = etree.Element('test') cls = DateTime(as_timezone=pytz.utc, timezone=False) XmlDocument().to_parent(None, cls, n, element, ns_test) element = element[0] c = n.astimezone(pytz.utc).replace(tzinfo=None) self.assertEquals(element.text, c.isoformat()) dt = XmlDocument().from_element(None, cls, element) assert dt.tzinfo is not None dt = dt.replace(tzinfo=None) self.assertEquals(c, dt)
class SubMessage(SmevModel): SubRequestNumber = Unicode(type_name="SubRequestNumber", min_occurs=1, max_occurs=1) Status = Unicode(type_name="Status", min_occurs=1, max_occurs=1, values=("REQUEST", "RESULT", "REJECT", "INVALID", "ACCEPT", "PING", "PROCESS", "NOTIFY", "FAILURE", "CANCEL", "STATE", "PACKET")) Originator = OrgExternalType(type_name="Originator", max_occurs=1) Date = DateTime(type_name="Date", min_occurs=1, max_occurs=1) RequestIdRef = Unicode(type_name="RequestIdRef", max_occurs=1) OriginRequestIdRef = Unicode(type_name="OriginRequestIdRef", max_occurs=1) ServiceCode = Unicode(type_name="ServiceCode", max_occurs=1) CaseNumber = Unicode(type_name="CaseNumber", max_occurs=1)
class TicketInfo(ComplexModel): __namespace__ = SOAP_NAMESPACE id = String(doc=u'Уникальный для ИС идентификатор заявки') ticketUid = String(doc=u'Уникальный для МИС ЛПУ идентификатор заявки') hospitalUid = String(doc=u'Уникальный идентификатор ЛПУ') doctorUid = Integer.customize(doc=u'Уникальный идентификатор врача') doctor = DoctorInfo.customize(max_occurs=1, doc=u'ФИО врача') person = PersonName.customize(max_occurs=1, doc=u'ФИО записавшегося') status = TicketStatus.customize(max_occurs=1, doc=u'Статус талончика') timeslotStart = DateTime( doc=u'Начало приёма у врача, соответствующее данной заявке') location = Unicode( doc=u'Информация о месте приёма (корпус, этаж, кабинет и т.п.)') comment = Unicode(doc=u'Дополнительные указания и информация') printableDocument = PrintableDocument() def __init__(self): super(TicketInfo, self).__init__(doc=u'Данные о текущем статусе заявки на приём')
class WFMPortalService(DjangoServiceBase): """WEB API""" __in_header__ = AuthDataHeader """ Создание заявки на аутсорсинг персонала """ @rpc(Unicode(sub_name='guid', min_occurs=1, nillable=False), HeadquaterSoapModel.customize(min_occurs=0, nillable=False), Date(sub_name='start'), Date(sub_name='end'), OrganizationSoapModel, AgencySoapModel, Unicode(sub_name='state', min_occurs=1, nillable=False), Array(ShiftSoapModel), Unicode(sub_name='comments', min_occurs=0, nillable=False), Unicode(sub_name='user_name', min_occurs=0, nillable=False), Unicode(sub_name='email', min_occurs=0, nillable=False), _returns=Unicode, _throws=[AuthenticationError, AuthorizationError, CustomError]) @soap_logger @check_auth_data def setOutsourcingRequest(ctx, guid, headquater, start, end, organization, agency, state, shifts, comments, user_name, email): auth_and_check_perms(ctx.in_header.login, ctx.in_header.password) # TODO remove if not headquater: db_headquarter = open_headquarter_by_code('mvideo') # Магазин, сформировавший запрос if headquater: db_headquarter = open_headquarter_by_code(headquater.code) db_organization = open_organization_by_code( organization.code, db_headquarter) else: db_organization = open_organization_by_code( organization.code, None) db_headquarter = db_organization.headquater if not db_headquarter: raise CustomError( f'REQUEST {guid}: no headquater with code {headquater.code}') if not db_organization: raise CustomError( f'REQUEST {guid}: no organiztion with code {organization.code}' ) # Агентство, в котором запрашиваем аутсорсинг db_agency = open_agency_by_code(agency.code, None) if not db_agency: raise CustomError( f'REQUEST {guid}: no agency with code {agency.code}') # Принимаем запросы только в состоянии launched, повторно запросы и запросы без смен не обрабатываем if state != 'launched': raise CustomError( f'REQUEST {guid}: state {state} is differ then launched') out_req = OutsourcingRequest.objects.filter(guid=guid).first() if out_req or not shifts: return {'result': 'ok'} # Создаем объект запроса if not comments: comments = '' if not user_name: user_name = '' if not email: email = '' out_req = OutsourcingRequest.objects.create( guid=guid, headquater=db_headquarter, organization=db_organization, agency=db_agency, state='accepted', start=start, end=end, comments=comments, user_name=user_name, email=email) # Создаем связанные с запросом смены for s in shifts: try: job = Job.objects.get(code=s.job.code) except Job.DoesNotExist: raise CustomError( f'REQUEST {guid}, SHIFT {s.guid}: no job with code {s.job.code}' ) if s.start > s.end: raise CustomError( f'REQUEST {guid}, SHIFT {s.guid}: start > end') if s.worktime < 0: raise CustomError( f'REQUEST {guid}, SHIFT {s.guid}: worktime = {s.worktime} < 0' ) OutsourcingShift.objects.create(guid=s.guid, headquater=db_headquarter, state=s.state, start=s.start, end=s.end, worktime=s.worktime, job=job, request=out_req, agency=db_agency, start_date=s.start) # Создаем и отправляем уведомления о новой заявке make_notify_data(out_req, 'agency', 'wait_req_template') return {'result': 'ok'} """ Получение данных по запросам, чей статус был обновлен раньше определенного времени """ @rpc(DateTime(sub_name='timestamp', min_occurs=1, nillable=False), HeadquaterSoapModel.customize(min_occurs=0, nillable=False), Integer(sub_name='amount', min_occurs=0, nillable=False), _returns=ComplexRequestsResponseSoapModel, _throws=[AuthenticationError, AuthorizationError, CustomError]) @soap_logger @check_auth_data def getOutsourcingRequests(ctx, dt_change, headquater, amount): auth_and_check_perms(ctx.in_header.login, ctx.in_header.password) # TODO remove if not headquater: db_headquarter = open_headquarter_by_code('mvideo') else: # Клиент db_headquarter = open_headquarter_by_code(headquater.code) if not db_headquarter: raise CustomError( f'Headquater {headquater.code} is not registered') response = dict() response['requests_list'] = [] # Ограничинваем максимальное количество запросов, возвращаемых за 1 раз if not amount or amount < 0: amount = 100 # Поиск смен out_requests = OutsourcingRequest.objects.filter( headquater=db_headquarter, dt_ready__gt=dt_change, state='ready') out_requests = out_requests.order_by('dt_ready')[:amount] # Формируем результат if not out_requests: response['result'] = len(out_requests) response['timestamp'] = dt_change else: response['result'] = len(out_requests) response['timestamp'] = out_requests.aggregate( timestamp=Max('dt_ready'))['timestamp'] response['requests_list'] = out_requests return response """ Получение данных по запросу и связанным с ним сменам """ @rpc(Unicode(sub_name='guid', min_occurs=1, nillable=False), HeadquaterSoapModel.customize(min_occurs=0, nillable=False), _returns=ComplexOutsourcingRequestSoapModel, _throws=[AuthenticationError, AuthorizationError, CustomError]) @soap_logger @check_auth_data def getOutsourcingRequest(ctx, guid, headquater): auth_and_check_perms(ctx.in_header.login, ctx.in_header.password) # TODO remove if not headquater: db_headquarter = open_headquarter_by_code('mvideo') else: # Клиент db_headquarter = open_headquarter_by_code(headquater.code) if not db_headquarter: raise CustomError( f'Headquater {headquater.code} is not registered') try: out_request = OutsourcingRequest.objects.get( guid=guid, headquater=db_headquarter) shifts = OutsourcingShift.objects.filter( request=out_request, headquater=db_headquarter).select_related('job') out_request.shifts = shifts return out_request except: raise CustomError( f'REQUEST {guid}: no OutsourcingRequest is found') """ Получение изменений по сменам на аутсорсинг """ @rpc(DateTime(sub_name='timestamp', min_occurs=1, nillable=False), HeadquaterSoapModel.customize(min_occurs=0, nillable=False), Integer(sub_name='amount', min_occurs=0, nillable=False), _returns=ComplexShiftsResponseSoapModel, _throws=[AuthenticationError, AuthorizationError, CustomError]) @soap_logger @check_auth_data def getOutsourcingShifts(ctx, dt_change, headquater, amount): auth_and_check_perms(ctx.in_header.login, ctx.in_header.password) # TODO remove if not headquater: db_headquarter = open_headquarter_by_code('mvideo') else: # Клиент db_headquarter = open_headquarter_by_code(headquater.code) if not db_headquarter: raise CustomError( f'Headquater {headquater.code} is not registered') response = dict() response['shifts_list'] = [] # Ограничинваем максимальное количество смен, возвращаемых за 1 раз if not amount or amount < 0: amount = 100 # Поиск смен out_shifts = OutsourcingShift.objects.filter(headquater=db_headquarter, dt_change__gt=dt_change, state='accept') out_shifts = out_shifts.order_by('dt_change').select_related( 'agency_employee')[:amount] # Получение ТН сотрудника в организации на основе OrgHistory for shift in out_shifts: if shift.agency_employee: shift.agency_employee.oh_number = shift.get_employee_number_in_organization( ) # Формируем результат if not out_shifts: response['result'] = len(out_shifts) response['timestamp'] = dt_change else: response['result'] = len(out_shifts) response['timestamp'] = out_shifts.aggregate( timestamp=Max('dt_change'))['timestamp'] response['shifts_list'] = out_shifts return response """ Получение смен промоутеров """ @rpc(DateTime(sub_name='timestamp', min_occurs=1, nillable=False), HeadquaterSoapModel.customize(min_occurs=0, nillable=False), AgencySoapModel.customize(min_occurs=0, nillable=False), Integer(sub_name='amount', min_occurs=0, nillable=False), _returns=ComplexPromoShiftsResponseSoapModel, _throws=[AuthenticationError, AuthorizationError, CustomError]) @soap_logger @check_auth_data def getPromoShifts(ctx, dt_change, headquater, agency, amount): return _calc_shifts(ctx, dt_change, headquater, agency, amount, party='promo') """ Получение смен брокеров """ @rpc(DateTime(sub_name='timestamp', min_occurs=1, nillable=False), HeadquaterSoapModel.customize(min_occurs=0, nillable=False), AgencySoapModel.customize(min_occurs=0, nillable=False), Integer(sub_name='amount', min_occurs=0, nillable=False), _returns=ComplexPromoShiftsResponseSoapModel, _throws=[AuthenticationError, AuthorizationError, CustomError]) @soap_logger @check_auth_data def getBrokerShifts(ctx, dt_change, headquater, agency, amount): return _calc_shifts(ctx, dt_change, headquater, agency, amount, party='broker') """ Удаление смены из заявки на аутсорсинг по решению управляюего магазином """ @rpc(Array(ShiftDeleteSoapModel), HeadquaterSoapModel.customize(min_occurs=0, nillable=False), _returns=Unicode, _throws=[AuthenticationError, AuthorizationError, CustomError]) @soap_logger @check_auth_data def deleteOutsourcingShifts(ctx, shifts, headquater): auth_and_check_perms(ctx.in_header.login, ctx.in_header.password) # TODO remove if not headquater: db_headquarter = open_headquarter_by_code('mvideo') else: # Клиент db_headquarter = open_headquarter_by_code(headquater.code) if not db_headquarter: raise CustomError( f'Headquater {headquater.code} is not registered') # Выходим, если массив смен не задан if not shifts: return {'result': 'ok'} # Помечаем смены как удаленные и формируем уведомления for shift in shifts: # ---------------------------------------------------------- out_shift = OutsourcingShift.objects.filter( guid=shift.guid, headquater=db_headquarter).first() if not out_shift: continue # Создаем и отправляем уведомления об удаленной смене make_notify_data(out_shift, 'agency', 'delete_shift_template') # Меняем состояние на удалена out_shift.state = 'delete' out_shift.save(update_fields=['state']) # ----------------------------------------------------------- return {'result': 'ok'} """ Получение изменений в данных сотрудников """ @rpc(DateTime(sub_name='timestamp', min_occurs=1, nillable=False), HeadquaterSoapModel.customize(min_occurs=0, nillable=False), Integer(sub_name='amount', min_occurs=1, nillable=False), _returns=ComplexEmployeeEventResponseSoapModel, _throws=[AuthenticationError, AuthorizationError, CustomError]) @soap_logger @check_auth_data def getEmployeeEvents(ctx, timestamp, headquater, amount): auth_and_check_perms(ctx.in_header.login, ctx.in_header.password) # Ограничинваем максимальное количество событий, возвращаемых за 1 раз if amount <= 0: amount = 100 # TODO remove if not headquater: db_headquarter = open_headquarter_by_code('mvideo') else: # Клиент db_headquarter = open_headquarter_by_code(headquater.code) if not db_headquarter: raise CustomError( f'Headquater {headquater.code} is not registered') # Поиск событий, начиная с заданного в запросе timestamp response = dict() response['events_list'] = [] events = EmployeeEvent.objects.filter(dt_created__gt=timestamp, headquater=db_headquarter). \ select_related('agency_employee', 'agency').order_by('id')[:amount] # Обогощаем найденные события доп. полями for event in events: # Тип агентства event.agency.party = event.agency.headquater.party # Документы сотрудника event.agency_employee.documents = EmployeeDoc.objects.filter( agency_employee=event.agency_employee).order_by('-id') # Обнуляем лишние поля if event.kind != 'recruitment': event.recruitment_date = None if event.kind != 'dismissal': event.dismissal_reason = None event.dismissal_date = None event.blacklist = None # Добавляем возвращемые события в ответное сообщение response['result'] = len(events) if events: response['timestamp'] = events.aggregate( timestamp=Max('dt_created'))['timestamp'] response['events_list'] = events return response """DEPRICATED""" @rpc(HeadquaterSoapModel.customize(min_occurs=1, nillable=False), OrganizationSoapModel.customize(min_occurs=1, nillable=False), AgencySoapModel.customize(min_occurs=1, nillable=False), EmployeeMinSoapModel, EventSoapModel.customize(sub_name='event'), Unicode(sub_name='kind', min_occurs=1, nillable=False), Unicode(sub_name='number', min_occurs=0, nillable=False), Date(sub_name='recruitment_date', min_occurs=0, nillable=False), Date(sub_name='recruitment_state', min_occurs=0, nillable=False), Date(sub_name='dismissal_date', min_occurs=0, nillable=False), Unicode(sub_name='reject_reason', min_occurs=0, nillable=False), Unicode(sub_name='dismissal_reason', min_occurs=0, nillable=False), _returns=Unicode, _throws=[AuthenticationError, AuthorizationError, CustomError]) @soap_logger @check_auth_data def setEventHistory(ctx, headquater, organization, agency, employee, employeeevent, kind, number, recruitment_date, recruitment_state, dismissal_date, reject_reason, dismissal_reason): raise CustomError('Method is deprocated') # TODO изменить проверку доступа с is_superuser auth_and_check_perms(ctx.in_header.login, ctx.in_header.password) headquater_id = get_headquater_id(headquater.code) org = Organization.objects.get(code=organization.code, headquater_id=headquater_id) if not org: raise CustomError('No organiztion') agn = Agency.objects.get(code=agency.code) if not agn: raise CustomError('No agency') emp = AgencyEmployee.objects.get(number=employee.number, agency=agn) if not emp: raise CustomError('No employee') event = EmployeeEvent.objects.get(guid=employeeevent.guid) user = User.objects.get(username=ctx.in_header.login) if kind not in dict(EVENT_HISTORY_KIND_CHOICES): raise CustomError('No kind') elif kind == 'accept_recruitment': if not recruitment_date: raise CustomError('No recruitment_date') if recruitment_state not in ['active', 'inactive']: raise CustomError('No recruitment_state') """Создаем объект внешнего события""" EmployeeHistory.objects.create(user=user, headquater_id=headquater_id, organization=org, event=event, agency_employee=emp, agency=agn, kind=kind, recruitment_date=recruitment_date, recruitment_state=recruitment_state) if recruitment_state == 'active': """Создаем объект назначения""" OrgHistory.objects.create(headquater_id=headquater_id, organization=org, agency_employee=emp, number=number, start=recruitment_date) """Устанавливаем EmployeeEvent флаг, что ответ на него получен""" event.answer_received = True event.save(update_fields=['answer_received']) elif kind == 'reject_recruitment': if not reject_reason: raise CustomError('No reject_reason') """Создаем объект внешнего события""" EmployeeHistory.objects.create(user=user, headquater_id=headquater_id, organization=org, event=event, agency_employee=emp, agency=agn, kind=kind, reject_reason=reject_reason) """Устанавливаем EmployeeEvent флаг, что ответ на него получен""" event.answer_received = True event.save(update_fields=['answer_received']) elif kind == 'dismissal': if not dismissal_date or not dismissal_reason: raise CustomError('No dismissal date or reason') """Ищем назначение и устанавливаем дату увольнения""" org_history = OrgHistory.objects.get(organization=org, agency_employee=emp) if not org_history: raise CustomError('No OrgHistory') org_history.end = dismissal_date - timedelta(days=1) org_history.save(update_fields=['end']) """Ищем смены данного сотрудника после даты увольнения и снимаем назначение""" OutsourcingShift.objects.filter( agency_employee=emp, start_date__gt=dismissal_date - timedelta(days=1), headquater_id=headquater_id).update(agency_employee=None) """Создаем объект внешнего события""" EmployeeHistory.objects.create(user=user, headquater_id=headquater_id, organization=org, event=event, agency_employee=emp, agency=agn, kind=kind, dismissal_date=dismissal_date, dismissal_reason=dismissal_reason) """Устанавливаем EmployeeEvent флаг, что ответ на него получен""" event.answer_received = True event.save(update_fields=['answer_received']) """Устанавливаем сотруднику дату обновления данных по API""" event.agency_employee.last_external_update = timezone.now() event.agency_employee.save(update_fields=['last_external_update']) return "ok" """Подтверждение или отказ в приеме сотрудника из кадровой системы клиента""" @rpc(EventSoapModel2.customize(sub_name='event', min_occurs=1, nillable=False), Unicode(sub_name='status', min_occurs=1, nillable=False), Unicode(sub_name='recruitmentState', min_occurs=0, nillable=False, default='active'), Date(sub_name='recruitmentDate', min_occurs=0, nillable=False), Unicode(sub_name='externalNumber', min_occurs=0, nillable=False), Unicode(sub_name='rejectReason', min_occurs=0, nillable=False), _returns=Unicode, _throws=[AuthenticationError, AuthorizationError, CustomError]) @soap_logger @check_auth_data def setRecruitmentStatus(ctx, employeeevent, status, recruitmentState, recruitmentDate, externalNumber, rejectReason): user = User.objects.get(username=ctx.in_header.login) auth_and_check_perms(ctx.in_header.login, ctx.in_header.password) # Проверка параметров event = EmployeeEvent.objects.get(guid=employeeevent.guid) if not event: raise CustomError(f'Event {employeeevent.guid} is undefined') if recruitmentState and recruitmentState not in ['active', 'inactive']: raise CustomError('No recruitmentState') if status not in ['accept', 'reject']: return # Подтверждение регистрации if status == 'accept': error = accept_employee_attach(user, event, recruitmentState, recruitmentDate, externalNumber) # Регистрация отклонена else: error = reject_employee_attach(user, event, rejectReason) # Обработчик ошибок if error: raise CustomError(error) # Устанавливаем сотруднику дату обновления данных по API event.agency_employee.last_external_update = timezone.now() event.agency_employee.save(update_fields=['last_external_update']) return """Открепление сотрудника от клиента по запросу из кадровой системы""" @rpc(HeadquaterSoapModel.customize(min_occurs=1, nillable=False), OrganizationSoapModel, AgencySoapModel.customize(min_occurs=1, nillable=False), Unicode(sub_name='externalNumber', min_occurs=1, nillable=False), Date(sub_name='dismissalDate', min_occurs=1, nillable=False), Unicode(sub_name='dismissalReason', min_occurs=1, nillable=False), Boolean(sub_name='blacklist', min_occurs=1, nillable=False), _returns=Unicode, _throws=[AuthenticationError, AuthorizationError, CustomError]) @soap_logger @check_auth_data def dismissEmployee(ctx, headquater, organization, agency, ext_number, dismissal_date, dismissal_reason, blacklist): user = User.objects.get(username=ctx.in_header.login) auth_and_check_perms(ctx.in_header.login, ctx.in_header.password) # Проверка параметров db_headquarter = open_headquarter_by_code(headquater.code) if not db_headquarter: raise CustomError(f'Headquater {headquater.code} is not found') if organization: db_organization = open_organization_by_code( organization.code, db_headquarter) if not db_organization: raise CustomError( f'Organization {organization.code} is not found') else: db_organization = None db_agency = open_agency_by_code(agency.code, None) if not db_agency: raise CustomError(f'Agency {agency.code} is not found') # Определяем увольняемого сотрудника employees = employees_by_ext_number(db_headquarter, db_agency, ext_number) for employee in employees: dismiss_employee(user, employee, dismissal_date, dismissal_reason, blacklist, db_headquarter, db_organization) # Устанавливаем сотруднику дату обновления данных по API employee.last_external_update = timezone.now() employee.save(update_fields=['last_external_update']) return ######## @rpc(HeadquaterSoapModel.customize(min_occurs=1, nillable=False), Array(OrgunitSoapModel.customize(min_occurs=1, nillable=False)), Array(OrglinkSoapModel.customize(min_occurs=0, nillable=False)), _returns=Unicode, _throws=[AuthenticationError, AuthorizationError, CustomError]) @soap_logger @check_auth_data def setOrgunits(ctx, headquater, orgunits, orglinks): """Set Orgunits. Синхронизитрует орг. структуру на основе данных из портала планирования""" auth_and_check_perms(ctx.in_header.login, ctx.in_header.password) # Headquarter headquater_id = get_headquater_id(headquater.code) # Organizations orgunits_received = 0 orgunits_created = 0 orgunits_errors = 0 if orgunits: for orgunit in orgunits: orgunits_received += 1 org, org_created = Organization.objects.get_or_create( code=orgunit.code, headquater_id=headquater_id) if org_created: orgunits_created += 1 org.name = orgunit.name org.address = orgunit.address org.kind = 'store' if orgunit.parent and org_created: parent_org = Organization.objects.filter( code=orgunit.parent.code, headquater_id=headquater_id).first() if parent_org: org.parent = parent_org else: default, default_created = Organization.objects.get_or_create( code=headquater.code + '_city_undefined', name='Город не определен', headquater_id=headquater_id, kind='city') org.parent = default org.last_external_update = timezone.now() org.save() # OrgLinks orglinks_received = 0 orglinks_created = 0 orglinks_errors = 0 if orglinks: for orglink_imp in orglinks: orglinks_received += 1 organization = Organization.objects.filter( code=orglink_imp.organization.code).first() if not organization: orglinks_errors += 1 continue agency = Agency.objects.filter( code=orglink_imp.agency.code).first() if not agency: orglinks_errors += 1 continue _, orglink_created = OrgLink.objects.get_or_create( agency=agency, organization=organization, headquater_id=headquater_id) if orglink_created: orglinks_created += 1 return { 'result': 'ok', 'orgunits_received': orgunits_received, 'orgunits_created': orgunits_created, 'orgunits_errors': orgunits_errors, 'orglinks_received': orglinks_received, 'orglinks_created': orglinks_created, 'orglinks_errors': orglinks_errors, } @rpc(HeadquarterSoapModel.customize(min_occurs=1, nillable=False), UserExtSoapModel.customize(sub_name='user', min_occurs=1, nillable=False), Array(AccessProfileSoapModel, sub_name='accessProfiles').customize(min_occurs=1, nillable=False), _throws=[ AuthenticationError, AuthorizationError, error.ResourceNotFoundError ]) @soap_logger @check_auth_data def setUser(ctx, headquarter, user, access_list): auth_and_check_perms(ctx.in_header.login, ctx.in_header.password) # Обновляем или создаем сотрудника user_defaults = { 'first_name': user.first_name, 'last_name': user.last_name, 'email': user.email, 'is_active': user.is_active } db_user, created = User.objects.update_or_create( username=user.username, defaults=user_defaults) db_headquarter = open_headquarter_by_code(headquarter.code) db_access_role = None # Установка прав доступа if access_list is None: access_list = [] for access_profile in access_list: try: db_organization = open_organization_by_code( access_profile.unit.code, db_headquarter) except error.ResourceNotFoundError: continue if access_profile.role is not None: db_access_role = open_role_by_code(access_profile.role.code) if db_access_role is None: raise error.ResourceNotFoundError('accessRole') profile, _ = AccessProfile.objects.update_or_create( user=db_user, unit_type=ContentType.objects.get_for_model(db_organization), unit_id=db_organization.id, role=db_access_role, headquater=db_headquarter)
class HeaderType(SmevModel): NodeId = Unicode(type_name="NodeId") MessageId = Unicode(type_name="MessageId") TimeStamp = DateTime(type_name="TimeStamp") MessageClass = Unicode(type_name="MessageClass", values=["REQUEST", "RESPONSE"])