openapi: 3.1.0
info:
  title: Integração Master Data
  version: 1.0.0
  description: |
    API para envio de dados de colaboradores, gerentes, departamentos, regiões e funções (cargos) para atualização na Fhinck.

    - Autenticação via campo `key` no corpo (JSON)
    - Endpoint único e final
    - Recomenda-se envio diário de deltas
servers:
  - url: https://integrations.fhinck.com
    description: Produção
  - url: https://integrations-hml.fhinck.com
    description: Homologação
paths:
  /masterData:
    post:
      summary: Atualiza dados Master Data
      description: |
        Recebe dados de colaboradores, gerentes, departamentos, regiões e funções para criação/atualização,
        e opcionalmente DEVOLVE o que está gravado.

        - `data` grava. `read` devolve. Pelo menos um dos dois é obrigatório; sem nenhum, retorna 422.
        - `read: ["employees"]` + `ids: [...]` devolve o cadastro MAIS RECENTE de cada login
          informado, mais a lista `notFound` com os logins que não existem. Somente leitura.
        - `read: ["shifts"]` devolve todos os turnos da empresa (comportamento já existente,
          inalterado).
        - Os dois modos podem ser combinados na mesma chamada, inclusive junto de `data` —
          nesse caso a gravação acontece primeiro e a resposta traz o que ficou gravado.
        - Pedido de leitura malformado é recusado ANTES da gravação: nada é gravado pela metade.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/MasterDataRequest"
            examples:
              exemploBasico:
                summary: Exemplo completo de request
                value:
                  key: SUA_CHAVE_DE_AUTENTICACAO
                  data:
                    employees:
                      - login: maria.silva
                        name: Maria Silva
                        department: Derrgerg
                        department_path: Duburvu_Derrgerg
                        role: Retbrbbeb
                        region: SP
                        active: true
                        vacation: true
                        vacation_date_in: "2024-12-01"
                        vacation_date_out: "2024-10-10"
                        interface:
                          punch_clock_active: true
                          collector_control_disabled: true
                          journey_type: flex
                          begin_journey:
                            monday: "08:00:00"
                            tuesday: "08:00:00"
                          journey_time:
                            monday: 540
                            tuesday: 540
                            wednesday: 540
                            thursday: 540
                            friday: 540
                    managers:
                      - email: joao.souza@empresa.example
                        name: João Souza
                        department: Derrgerg
                        department_path: Duburvu_Derrgerg
                        region: SP
                        active: true
                        role: Rvuevnrirovn
                        whatsapp: "5511900000000"
                        profile: admin
                    departments:
                      - code: Duburvu
                        name: Gerência
                        department_level: 1
                      - code: Derrgerg
                        name: Coordenação
                        department_level: 2
                    regions:
                      - code: SP
                        name: São Paulo
                    roles:
                      - code: Rvuevnrirovn
                        name: Coordenador
                      - code: Retbrbbeb
                        name: Analista
      responses:
        "200":
          description: Sucesso
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SuccessResponse"
              examples:
                ok:
                  value:
                    err: false
                    message: Atualização concluída com sucesso!
                    summary:
                      regions: 1
                      roles: 2
                      departments: 2
                      employees: 1
                      managers: 1
                      shifts: 0
                      shiftAssignments: 0
        "400":
          description: Invalid key
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "422":
          description: Missing required fields
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
components:
  schemas:
    EmployeeSnapshot:
      type: object
      description: |
        Linha INTEIRA do cadastro mais recente do colaborador, como esta na base — sem recorte.
        Campos novos que a tabela ganhar passam a aparecer aqui automaticamente.
      properties:
        creation_user:
          type: string
          nullable: true
          description: |
            Procedencia do registro: o que o criou. Pode ser a marca de um processo
            (ex.: REORG-2026-06-26, INTEGRATION) ou quem originou a alteracao. E o campo que
            responde "por que este cadastro esta assim".
        fk_process_code:
          type: string
          nullable: true
          description: Codigo do processo. Nao preenchido pelo cadastro de colaborador.
        process_path:
          type: string
          nullable: true
          description: Caminho hierarquico do processo. Nao preenchido pelo cadastro de colaborador.
        employee:
          type: string
          description: Login do colaborador.
        employee_id:
          type: string
          nullable: true
          description: Identificador do colaborador na empresa (matricula, CPF, PIS).
        employee_alias:
          type: string
          description: Nome de exibicao do colaborador.
        fk_department_code:
          type: string
          description: Codigo do departamento.
        department_path:
          type: string
          description: Caminho hierarquico completo do departamento.
        fk_role_code:
          type: string
          nullable: true
          description: Codigo do cargo.
        fk_region_code:
          type: string
          nullable: true
          description: Codigo da regiao.
        active:
          type: boolean
        vacation_active:
          type: boolean
        vacation_date_in:
          type: string
          nullable: true
          format: date-time
        vacation_date_out:
          type: string
          nullable: true
          format: date-time
        Entry_Weekday:
          type: string
          nullable: true
          description: Inicio de jornada em dia util (HH:mm:ss).
        Exit_Weekday:
          type: string
          nullable: true
        Entry_Saturday:
          type: string
          nullable: true
        Exit_Saturday:
          type: string
          nullable: true
        Entry_Sunday:
          type: string
          nullable: true
        Exit_Sunday:
          type: string
          nullable: true
        search_date:
          type: string
          format: date-time
          description: Data de vigencia do registro.
        creation_date:
          type: string
          format: date-time
          description: Quando este registro foi gravado.
    MasterDataRequest:
      type: object
      required: [key]
      description: |
        `data` grava; `read` devolve. Pelo menos um dos dois e obrigatorio — chamada sem
        nenhum dos dois responde 422.
      properties:
        key:
          type: string
          description: Chave única de autenticação do cliente
        read:
          type: array
          description: |
            O que devolver na resposta, alem de gravar. ADITIVO — quem nao usa `read` continua
            chamando o endpoint exatamente como antes.
              - `shifts`    : devolve TODOS os turnos da empresa (nao usa `ids`).
              - `employees` : devolve o cadastro MAIS RECENTE de cada login em `ids`.
            Os dois podem vir juntos. Apenas UMA entidade por `ids` por chamada.
          items:
            type: string
            enum: [shifts, employees]
          example: [employees]
        ids:
          type: array
          description: |
            Logins a consultar quando `read` inclui `employees`. Maximo 5000 por chamada;
            repetidos contam uma vez. Maiusculas/minusculas e espacos nas pontas sao ignorados.
            Obrigatorio quando `read` inclui `employees`; sem ele a resposta e 422.
          minItems: 1
          maxItems: 5000
          items:
            type: string
          example: [michel, maria.silva]
        data:
          type: object
          required: [employees]
          properties:
            employees:
              type: array
              description: Lista de colaboradores
              items:
                $ref: "#/components/schemas/Employee"
            managers:
              type: array
              description: Lista de gerentes
              items:
                $ref: "#/components/schemas/Manager"
            departments:
              type: array
              description: Lista de departamentos
              items:
                $ref: "#/components/schemas/Department"
            regions:
              type: array
              description: Lista de regiões
              items:
                $ref: "#/components/schemas/Region"
            roles:
              type: array
              description: Lista de funções (cargos)
              items:
                $ref: "#/components/schemas/Role"
    Employee:
      type: object
      required: [login, name, department, role, active]
      properties:
        login:
          type: string
          description: Identificador único do colaborador
        name:
          type: string
          description: Gravado e devolvido em letras maiúsculas.
        department:
          type: string
          description: Código do departamento
        department_path:
          type: string
          description: "Caminho hierárquico do departamento (ex.: D1424_D44554)"
        region:
          type: string
          description: Código da região
        role:
          type: string
          description: Código da função (cargo)
        active:
          type: boolean
          default: true
        vacation:
          type: boolean
          default: false
        vacation_date_in:
          type: string
          format: date
        vacation_date_out:
          type: string
          format: date
        interface:
          $ref: "#/components/schemas/InterfaceConfig"
    InterfaceConfig:
      type: object
      required: [punch_clock_active, journey_type]
      properties:
        punch_clock_active:
          type: boolean
          default: true
        journey_type:
          type: string
          enum: [classic, flex]
          default: flex
        ask_journey_extension_timeout:
          type: integer
          default: 0
        lock_out_of_journey:
          type: boolean
          default: false
        lock_by_punch:
          type: boolean
          default: true
        lock_by_punch_delay:
          type: integer
          default: 0
        auth:
          type: object
          properties:
            token_period:
              type: string
            token_scope:
              type: string
        margin_for_time_limits:
          type: integer
          default: 0
        journey_first_period_time:
          type: integer
          default: 0
        journey_interval_time:
          type: integer
          default: 0
        journey_edit_enabled:
          type: boolean
          default: false
        journey_max_history:
          type: integer
          default: 31
        extra_time:
          type: object
          properties:
            allowed:
              type: boolean
              default: true
        justification_list:
          type: array
          items:
            type: object
            properties:
              activity:
                type: string
        collector_control_disabled:
          type: boolean
          default: true
        begin_journey:
          type: object
          additionalProperties:
            type: string
            pattern: '^([01]\d|2[0-3]):[0-5]\d:[0-5]\d$'
        end_journey:
          type: object
          additionalProperties:
            type: string
            pattern: '^([01]\d|2[0-3]):[0-5]\d:[0-5]\d$'
        begin_lunch_time:
          type: object
          additionalProperties:
            type: string
            pattern: '^([01]\d|2[0-3]):[0-5]\d:[0-5]\d$'
        end_lunch_time:
          type: object
          additionalProperties:
            type: string
            pattern: '^([01]\d|2[0-3]):[0-5]\d:[0-5]\d$'
        journey_time:
          type: object
          additionalProperties:
            type: integer
    Manager:
      type: object
      required: [email, name, department, active, role, profile]
      properties:
        email:
          type: string
          format: email
        name:
          type: string
        department:
          type: string
        department_path:
          type: string
        region:
          type: string
        active:
          type: boolean
          default: true
        role:
          type: string
        whatsapp:
          type: string
          description: "Número em formato internacional, somente dígitos (ex.: 5511900000000)"
        profile:
          type: string
          enum: [admin, analytics, approver2, ti, approver6]
          default: approver2
          description: "approver6 = sócio (Partner): mesmo acesso de approver2 ao dashboard e marca a pessoa como sócia para a aprovação de extensões acima de 2 horas. Enviar em minúsculas."
    Department:
      type: object
      required: [code, name]
      properties:
        code:
          type: string
          description: Identificador único do departamento
        name:
          type: string
        department_level:
          type: integer
    Region:
      type: object
      required: [code, name]
      properties:
        code:
          type: string
          description: Identificador único da região
        name:
          type: string
    Role:
      type: object
      required: [code, name]
      properties:
        code:
          type: string
          description: Identificador único da função (cargo)
        name:
          type: string
    SuccessResponse:
      type: object
      properties:
        err:
          type: boolean
          enum: [false]
          description: Booleano `false` no sucesso (nunca o texto "false").
        message:
          type: string
          example: Atualização concluída com sucesso!
        summary:
          type: object
          description: |
            Quantos itens de cada entidade vieram no `data` deste envio (o que foi enviado para gravação).
            Numa consulta pura (só `read`), vem zerado; as contagens da consulta ficam em `read`.
          properties:
            regions: { type: integer }
            roles: { type: integer }
            departments: { type: integer }
            employees: { type: integer }
            managers: { type: integer }
            shifts: { type: integer }
            shiftAssignments: { type: integer }
        employees:
          type: array
          description: |
            Presente quando `read` inclui `employees`. Um item por login ENCONTRADO, com o
            registro de cadastro mais recente de cada.
          items:
            $ref: "#/components/schemas/EmployeeSnapshot"
        read:
          type: object
          description: Presente quando `read` inclui `employees`. Contagem do que foi consultado.
          properties:
            entity:
              type: string
              example: employees
            requested:
              type: integer
              description: Logins distintos e validos recebidos em `ids`.
            found:
              type: integer
            notFound:
              type: integer
        notFound:
          type: array
          description: |
            Presente quando `read` inclui `employees`. Logins pedidos que NAO existem no
            cadastro desta empresa — dispensa comparar as duas listas do lado de quem integra.
          items:
            type: string
        shifts:
          type: array
          description: Presente quando `read` inclui `shifts`. Todos os turnos da empresa.
          items:
            type: object

    ErrorResponse:
      type: object
      properties:
        error:
          type: string
          example: Invalid key
