Árvore de páginas

Versões comparadas

Chave

  • Esta linha foi adicionada.
  • Esta linha foi removida.
  • A formatação mudou.

 Este documento é material de especificação dos requisitos de inovação, trata-se de conteúdo extremamente técnico.

                                                             
  



Informações Gerais

 

Especificação

Produto

Microsiga Protheus

Módulo

SIGAWMS - Gestão de Armazenagem

Segmento Executor

Distribuição e

Supply Chain - Logística

Projeto

1

M_DL_WMS002

IRM

1

PCREQ-

_

9339

Requisito

1

PCREQ-

_

9340

Subtarefa

1

PDRDL-

_

Chamado2

 

2452

Release de Entrega Planejada

11.80.14


Réplica

 


País

(

x

X ) Brasil  (  ) Argentina  (  )

Mexico

México  (  ) Chile  (  ) Paraguai  (  ) Equador

(  ) USA  (  )

Colombia  

Colômbia   (  ) Outro _____________.

Outros

 

   Legenda: 1 – Inovação 2 – Manutenção (Os demais campos devem ser preenchidos para ambos os processos). 


Objetivo

Permitir a junção (aglutinação) de quantidades iguais de um mesmo produto dentro de uma mesma carga ou, prevendo alterações futuras, de um mesmo plano de movimentação a fim de otimizar as movimentações

Objetivo

O plano de expedição consiste na aglutinação dos mesmos produtos de diferentes cargas/pedidos ao executar uma ordem de serviço de expedição. A ideia é que seja possível selecionar as ordens de serviço que serão consideradas na aglutinação. Neste primeiro momento, é levado em consideração apenas produtos de pedidos da mesma montagem de carga, posteriormente será criado uma tela para selecionar inclusive pedidos de cargas diferentes. Esta ação otimiza a busca de saldo no armazém priorizando a expedição de endereços de tipo pulmão quando a junção dos pedidos que compõe o a carga ou plano solicitarem uma quantidade maior que uma norma do produto.

Esta alteração, diferente da aglutinação dos movimentos das atividades, configurada pelo cadastro de tarefa x atividade, aglutina as quantidade das ordens de serviço que geram um movimento de uma norma, priorizando a retirado do pulmão de forma mais eficiente.

Adequar o processo de aglutinação para permitir as movimentações por onda (plano de movimentação), que possibilitará a aglutinação de serviços de entrada e saída independente da carga ou cliente, será criado na ordem de serviço a indicação de qual plano a ordem de serviço pertence e assim juntar as quantidades dos produtos. 


Definição da Regra de Negócio

 

Alteração:

A execução das ordens de serviço pelo WMSA150 realiza uma busca das DCF selecionadas e uma por uma posiciona no registro e chama o método ExecuteDCF, a ideia é logo após o posicionamento utilizar das características do registro para buscar as ordens que podem ser aglutinadas. Encontrado os dados, será somado a variável da quantidade do DCF posicionado no objeto com as quantidades de todas as ordens de serviço do array

e a partir desse ponto segue o fluxo normal

, mas será precisa alterar também o status de cada DCF, para que não seja executada em seguida, e a criação da DCR para respeitar o array de ordens aglutinadas encontradas, o que mantém o

funcionamento do estorno.

Detalhes Alteração:

Primeiramente, deve conter

relacionamento com a ordem de serviço original.

Primeiramente, é de conhecimento que a alteração é aplicável somente para o novo WMS, ou seja, o parâmetro MV_WMSNEW precisa estar igual a .T., assim como o ambiente de desenvolvimento.

Conter no dicionário o parâmetro MV_WMSACEX que pode ser criado aplicando o update WMSU0033, acessado via WMSUMAIN.

Alterar a classe WMSDTCOrdemServico

A alteração inicia-se com a criação

dos

de dois atributos da classe WMSDTCOrdemServico:

cPlnExp
  • cCodPln > Código do plano de
expedição
  • movimentação
  • aOrdAglu > Array de ordens de serviço aglutinadas

*Lembrando que a criação de cada atributo precisa vir com os métodos Getters e Setters correspondentes.

Como o atributo

cPlnExp

cCodPln da classe corresponde ao campo DCF_

PLNEXP

CODPLN que será criado, ele precisa ser considerado nos métodos LoadData (utilizar FieldPos ao atribuir o valor) , RecordDCF e UpdateDCF (utilizar o método Getter e Setter criado).

 

Quando o parâmetro MV_WMSACEX for diferente de '0' e o serviço em execução for de separação (Self:oServico:ChkSepara()), dentro

Dentro do método ExecuteDCF da classe WMSDTCOrdemServicoExecute

logo após a validação se o 'Self:cIdDCF' está preenchido

após as validações e antes de iniciar o bloco transaction, criar a chamada de um método que realizará a busca das ordens de serviço semelhantes e adicionará ao array aOrdAglu. Este método precisa ser criado na WMSDTCOrdemServico para futuras aplicações.

O select de busca precisa prever a informação do campo DCF_

PLNEXP

CODPLN e para o filtro deve ser utilizado os atributos da classe.

Quando o atributo cPlnExp possuir valor diferente de vazio, o

O filtro precisa respeitar

o plano de expedição,

serviço, armazém, produto, lote, sub-lote, endereço

e

, status diferente de '3=Executado' e quando o atributo cCodPln estiver preenchido, o plano, quando estiver vazio,

precisa

considerar

a carga

e a

função WMSCarga

função WMSCarga() e a carga ao invés do plano

de expedição

. Quando MV_WMSACEX for '2', considerar no filtro o cliente e loja somente quando o plano estiver vazio.

Prevendo alterações futuras referente ao plano de movimentação,

conforme exemplo:

o endereço que precisa ser considerado no select varia dependendo do serviço que está sendo executado. Quando for um serviço de separação (Self:oServico:ChkSepara()), considerar armazém e endereço origem, pelo contrário, armazém e endereço destino, conforme exemplo:

" SELECT DCF.DCF_ID, DCF.DCF_QUANT, DCF.R_E_C_N_O_ RECNODCF"
" FROM "+RetSqlName("DCF")+" DCF"
" WHERE

 

        

DCF.DCF_FILIAL = '"+xFilial("DCF")+"'"
" AND DCF.DCF_SERVIC = '"+Self:oServico:GetServico()+"'"
" AND DCF.DCF_CODPRO = '"+Self:oProdLote:GetProduto()+"'"
If !Empty(Self:GetPlnExp())
" AND DCF.DCF_PLNEXP = '"+Self:GetPlnExp()+"'"
ElseIf WmsCarga(Self:GetCarga())
If SuperGetMv("MV_

WMSACES

WMSACEX",.F.,"0") == '2' // Se aglutina por cliente
" AND DCF.DCF_CLIFOR = '"+Self:GetCliFor()+"'"
" AND DCF.DCF_

LOJA  

LOJA = '"+Self:GetLoja()+"'"
EndIf
" AND DCF.DCF_CARGA = '"+Self:GetCarga()+"'"
EndIf
If

!Empty(

Self:oServico:

GetPlnExp

ChkSepara(

)

)
" AND DCF.DCF_

PLNEXP

LOCAL = '"+Self:oOrdEndOri:

GetPlnExp

GetArmazem()+"'

ElseIf WmsCarga(Self:GetCarga())

"
" AND DCF.DCF_

CARGA

ENDER = '"+Self:oOrdEndOri:

GetCarga

GetEnder()+"'"

EndIf

Else
" AND DCF.DCF_

LOCAL 

LOCDES = '"+Self:

oOrdEndOri

oOrdEndDes:GetArmazem()+"'"
" AND DCF.DCF_

ENDER 

ENDDES = '"+Self:

oOrdEndOri

oOrdEndDes:GetEnder()+"'"
EndIf
" AND DCF.DCF_LOTECT = '"+Self:oProdLote:GetLoteCtl()+"'"
" AND DCF.DCF_NUMLOT = '"+Self:oProdLote:GetNumLote()+"'"
" AND DCF.DCF_STSERV <> '3'"
" AND DCF.R_E_C_N_O_ <> "+Self:GetRecno()
" AND DCF.D_E_L_E_T_ = ' '"

*Importante manter esta ordem no filtro do select para que o banco de dados utilize do índice mais apropriado

. Deixar um comentário a respeito

.

Retornar os campos DCF_ID

, DCF_NUMSEQ

, DCF_QUANT, R_E_C_N_O_

e

, adicionar cada linha no array

aOrdAglu.

aOrdAglu e criar na ultima posição um vetor vazio que posteriormente será carregado com as atividades do serviço e suas quantidades.

Este array sempre precisará conter pelo menos um registro, que será o DCF atual. Para isso, preencher a primeira posição os valores do objeto da DCF atual e depois com o que encontrar no select. No inicio do método, certificar que o array inicialize como vazio.

Inicializar uma variável nQtdOrdSer, que conterá a quantidade sumarizada da aglutinação, com o Self:nQuant do objeto atual e incrementar na mesma variável para cada DCF_QUANT retornado do select de ordens de serviço possíveis de aglutinação. Após isso, substituir o valor do Self:nQuant por nQtdOrdSer.

Ordenar o array por IDDCF com a função aSort para garantir a ordem na execução assim como as quantidades na hora da criação dos movimentos em passos posteriores.

No

Incrementar em uma variável o DCF_QUANT para que depois seja substituído a quantidade do objeto Self:nQuant pela quantidade sumarizada.

 

Voltando para o

método ExecuteDCF da classe WMSDTCOrdemServicoExecute, alterar o bloco que atualiza o status da DCF posicionada no objeto para repetir para cada recno do aOrdAglu

quando Len(aOrdAglu) > 0

. Criar um laço de repetição pelo tamanho do array aOrdAglu.

O bloco que precisa repetir para atualizar o status é:

// Atualiza status

Self:SetStServ('3')

Self:SetOk("")

Self:UpdateDCF()

Self:UpdStatus()

*Importante manter o funcionamento atual do método quando o sistema não utilizar a funcionalidade, ou seja, quando o parâmetro MV_WMSACEX for igual a '0'.

Porém será preciso reposicionar o objeto para atualizar cada DCF. Utilizar o método GoToDCF(nRecno) quando Len(aOrdAglu) > 1, passando o recno de cada DCF do array por parâmetro. Ao terminar o laço de atualização do status, é preciso voltar a DCF posicionada original para que o Self:UnLockDCF() realize sua função corretamente, assim como o restante do processo.

No método ExecutePrd, antes do comando 'For' de aProdutos, definir os campos na ultima posição do array aOrdAglu. Percorrer o tamanho de aOrdAglu e adicionar mais espaço para quando o produto for partes e então adicionar a quantidade multiplicada pelo múltiplo do componente neste sub-array de aOrdAglu.

Antes de chamar a execução da função (oFuncao:ExecFuncao) atribuir o array aOrdAglu ao objeto do movimento, assim como aRecD12 e aLibD12

Em WMSDTCMovimentosServicoArmazem método AssignD12 antes do comando 'For' de  aAtividade, realizar o rateio para a tarefa da quantidade total solicitada dentre os ID DCF que estão no array, isso determinará quanto cada ID DCF será atendido pela quantidade total do movimento, conforme exemplo:

nQtSol := Self:nQtdMovto

nOrdPrd := Self:oOrdServ:nProduto

nOrdTar := Self:oOrdServ:nTarefa

For nI := 1 To Len(Self:aOrdAglu)

aAgluMov := Self:aOrdAglu[nI][POSTAREFA][nOrdPrd][nOrdTar]

If (aAgluMov[POSQTDSOL] - aAgluMov[POSQTDATD]) > 0

aAgluMov[POSIDDCF] := Self:oOrdServ:GetIdDCF()

If nQtSol > (aAgluMov[POSQTDSOL] - aAgluMov[POSQTDATD])

nQtSol -= (aAgluMov[POSQTDSOL] - aAgluMov[POSQTDATD])

aAgluMov[POSQTDMOV] := (aAgluMov[POSQTDSOL] - aAgluMov[POSQTDATD]) //Utiliza todo o saldo

Else

aAgluMov[POSQTDMOV] := nQtSol

nQtSol := 0

EndIf

// Grava o total atendido

aAgluMov[POSQTDATD] += aAgluMov[POSQTDMOV]

If nQtSol == 0

Exit

EndIf

EndIf

Next nI

Ao final da execução das atividades será preciso zerar as quantidades distribuídas da movimentação, ou seja, zerar a posição com a quantidade da movimentação de todos os sub-arrays de aOrdAglu.

Assim como a atualização do status para cada ordem de serviço, é preciso criar os registros DCR das ordens aglutinadas. Na classe WMSDTCMovimentosServicoArmazem método RecordD12, alterar o bloco "Grava relacionamento movimento serviço armazém" para cada ordem de serviço do array

quando Len(aOrdAglu) > 0, substituindo...

conforme exemplo:

// Grava relacionamento movimento servico armazem

nOrdPrd := Self:oOrdServ:nProduto

nOrdTar := Self:oOrdServ:nTarefa

For nI := 1 To Len(Self:aOrdAglu)

aAgluMov := Self:aOrdAglu[nI][POSTAREFA][nOrdPrd][nOrdTar]

If aAgluMov[POSQTDMOV] > 0

cIdDCF := aAgluMov[POSIDDCF]

nQtdMovto := aAgluMov[POSQTDMOV]

nQtdMovto2 := ConvUm(Self:oMovPrdLot:GetProduto(),nQtdMovto,0,2)

oRelacMov:SetIdOrig

oRelacMov:SetIdDCF

(cIdDCF)

oRelacMov:

SetSequen(cSequen)

Pelos valores do array aOrdAglu, assim como a quantidade de cada DCF. Utilizar de uma variável auxiliar para atribuir a quantidade do array para não alterar a variável utilizada atualmente.

Os registros DCR desse movimento precisam ter o mesmo DCR_IDORI, que seria o iddcf do próprio objeto, não precisando ser alterado. DCR_IDMOV, DCR_IDOPER e DCR_QUANT com o mesmo valor do método. DCF_IDDCF e DCR_SEQUEN correspondente a cada registro do array.

Neste passo não é preciso voltar o objeto oRelacMov para o valor posicionado original, mas ele deve continuar com o funcionamento atual quando Len(aOrdAglu) == 0 e, como não estamos na classe WMSDTCOrdemServico, validar se o array tem sua definição correta (Type("Self:oOrdServ:aAgluDCF") == "A").

 

SetIdDCF(Self:aOrdAglu[nI][1])

oRelacMov:SetIdMovto(IIF(lAglutina,D12->D12_IDMOV,cIdMovto))

oRelacMov:SetIdOpera(IIF(lAglutina,D12->D12_IDOPER,cIdOpera))

oRelacMov:SetSequen(cSequen)

If oRelacMov:LoadData()

oRelacMov:SetQuant(oRelacMov:GetQuant()+nQtdMovto)

oRelacMov:SetQuant2(oRelacMov:GetQuant2()+nQtdMovto2)

oRelacMov:UpdateDCR()

Else

oRelacMov:SetQuant(nQtdMovto)

oRelacMov:SetQuant2(nQtdMovto2)

oRelacMov:RecordDCR()

EndIf

nQtdTotal += nQtdMovto

EndIf

Next nI

nQtdMovto := nQtdTotal

nQtdMovto2 := ConvUm(Self:oMovPrdLot:GetProduto(),nQtdMovto,0,2)

Finalmente, será preciso alterar o processo de conferência de saída para considerar o array de ordens de serviço aglutinadas. A conferência de saída (DLConfSai()) não deve gerar movimentos aglutinados, por isso é preciso considerar todos os identificados da DCF para que cada movimento seja criado com a quantidade correta. Em WMSBCCConferenciaSaida método ProcConfSai alterar o select das movimentações buscando por todos os identificadores da DCF do array ao invés do posicionado, conforme exemplo:

" AND DCR.DCR_IDDCF IN ('000001','000002','000003','000004') "

Criar no update do projeto (WMSNEWUPD) o campo com as informações abaixo em Dicionário de Dados.

Rotina

Tipo de Operação

Opção de Menu

Regras de Negócio

WMSDTCOrdemServico

Alteração

 

 



WMSDTCOrdemServicoExecute

Alteração

 

 



WMSDTCMovimentosServicoArmazem

Alteração

 



WMSNEWUPD

 

 
Alteração

Exemplo de Aplicação

:

  • Configurar

    o

    parâmetro

    MV_WMSACEX

    com

    o

    valor

    '1=Aglutina

    por

    Carga'

    ou

    '2=Aglutina

    por

    Carga/Cliente'.

  • Criar

    vários

    pedidos

    de

    venda

    que

    realizam

    montagem

    de

    carga

    e

    que

    geram

    o

    serviço

    WMS

    na

    montagem

    de

    carga,

    com

    os

    mesmos

    produtos

    entre

    eles.

  • Criar

    uma

    ou

    mais

    cargas

    com

    os

    pedidos

    criados.

  • Ao

    executar

    os

    serviços,

    os

    movimentos

    da

    D12

    devem

    juntar

    a

    quantidade

    dos

    produtos

    iguais

    em

    um

    único

    movimento

    respeitando

    a

    norma.

  • Verificar

    se

    os

    dados

    da

    DCR

    consistem.

  • Estornar

    e

    executar

    várias

    vezes

    para

    garantir

    que o estorno não deixe lixo na base 

    o saldo do produto.

Tabelas Utilizadas

  • DCF – Ordem de Serviço

  • D12 – Movimentos Serviço WMS

  • DCR – Relacionamento Movimentos Distribuição

 

 


Dicionário de Dados

Arquivo : DCF – Ordem de Serviço  

Campo

DCF_

PLNEXP

CODPLN

Tipo

C

Tamanho

6

Valor Inicial

 


Mandatório

Sim (  ) Não (x)

Descrição

Plano de Expedição

Código do plano de movimentação.

Título

Cód. Plano

Exped.

Picture

@!

Help de Campo

Código do plano de expedição.

 

 

 

 

Utilizado para indicar as ordens de serviço que terão seus produtos aglutinados.


 

 

Este documento é material de especificação dos requisitos de inovação, trata-se de conteúdo extremamente técnico.