/// <summary>
        /// Converts a <see cref="ReferenceTerm"/> instance to a <see cref="FhirCoding"/> instance.
        /// </summary>
        /// <param name="referenceTerm">The reference term.</param>
        /// <returns>Returns a FHIR coding instance.</returns>
        public static FhirCoding ToCoding(ReferenceTerm referenceTerm)
        {
            if (referenceTerm == null)
            {
                return(null);
            }

            traceSource.TraceEvent(EventLevel.Verbose, "Mapping reference term");

            var cs = referenceTerm.LoadProperty <CodeSystem>(nameof(ReferenceTerm.CodeSystem));

            return(new FhirCoding(new Uri(cs.Url ?? String.Format("urn:oid:{0}", cs.Oid)), referenceTerm.Mnemonic));
        }
Beispiel #2
0
        /// <summary>
        /// Create a trade item
        /// </summary>
        public TransactionalTradeItemType CreateTradeItem(Material material)
        {
            if (material == null)
            {
                throw new ArgumentNullException(nameof(material), "Missing material instance");
            }

            ReferenceTerm cvx = null;

            if (material.TypeConceptKey.HasValue)
            {
                cvx = ApplicationContext.Current.GetService <IConceptRepositoryService>().GetConceptReferenceTerm(material.TypeConceptKey.Value, "CVX");
            }
            var typeItemCode = new ItemTypeCodeType()
            {
                Value           = cvx?.Mnemonic ?? material.TypeConcept?.Mnemonic ?? material.Key.Value.ToString(),
                codeListVersion = cvx?.LoadProperty <CodeSystem>("CodeSystem")?.Authority ?? "OpenIZ-MaterialType"
            };

            // Manufactured material?
            if (material is ManufacturedMaterial)
            {
                var mmat = material as ManufacturedMaterial;
                var mat  = this.m_materialRepository.FindMaterial(o => o.Relationships.Where(r => r.RelationshipType.Mnemonic == "Instance").Any(r => r.TargetEntity.Key == mmat.Key)).FirstOrDefault();

                return(new TransactionalTradeItemType()
                {
                    additionalTradeItemIdentification = material.LoadCollection <EntityIdentifier>("Identifiers").Where(o => o.Authority.DomainName != "GTIN").Select(o => new AdditionalTradeItemIdentificationType()
                    {
                        Value = o.Value,
                        additionalTradeItemIdentificationTypeCode = o.LoadProperty <AssigningAuthority>("Authority").DomainName
                    }).ToArray(),
                    tradeItemClassification = new TradeItemClassificationType()
                    {
                        additionalTradeItemClassificationCode = mat.LoadCollection <EntityIdentifier>("Identifiers").Select(o => new AdditionalTradeItemClassificationCodeType()
                        {
                            Value = o.Value,
                            codeListVersion = o.LoadProperty <AssigningAuthority>("Authority").DomainName
                        }).ToArray()
                    },
                    gtin = material.Identifiers.FirstOrDefault(o => o.Authority.DomainName == "GTIN").Value,
                    itemTypeCode = typeItemCode,
                    tradeItemDescription = material.Names.Select(o => new Description200Type()
                    {
                        Value = o.Component.FirstOrDefault()?.Value
                    }).FirstOrDefault(),
                    transactionalItemData = new TransactionalItemDataType[]
                    {
                        new TransactionalItemDataType()
                        {
                            batchNumber = mmat.LotNumber,
                            itemExpirationDate = mmat.ExpiryDate.Value,
                            itemExpirationDateSpecified = true
                        }
                    }
                });
            }
            else // Material code
            {
                return(new TransactionalTradeItemType()
                {
                    tradeItemClassification = new TradeItemClassificationType()
                    {
                        additionalTradeItemClassificationCode = material.LoadCollection <EntityIdentifier>("Identifiers").Select(o => new AdditionalTradeItemClassificationCodeType()
                        {
                            Value = o.Value,
                            codeListVersion = o.LoadProperty <AssigningAuthority>("Authority").DomainName
                        }).ToArray()
                    },
                    itemTypeCode = typeItemCode,
                    tradeItemDescription = cvx?.LoadCollection <ReferenceTermName>("DisplayNames")?.Select(o => new Description200Type()
                    {
                        Value = o.Name
                    })?.FirstOrDefault() ??
                                           material.Names.Select(o => new Description200Type()
                    {
                        Value = o.Component.FirstOrDefault()?.Value
                    }).FirstOrDefault(),
                });
            }
        }
        /// <summary>
        /// Requests the issuance of a BMS1 inventory report request
        /// </summary>
        public LogisticsInventoryReportMessageType IssueInventoryReportRequest(LogisticsInventoryReportRequestMessageType parameters)
        {
            // Status
            LogisticsInventoryReportMessageType retVal = new LogisticsInventoryReportMessageType()
            {
                StandardBusinessDocumentHeader = this.m_gs1Util.CreateDocumentHeader("logisticsInventoryReport", null)
            };


            // Date / time of report

            DateTime?reportFrom = parameters.logisticsInventoryReportRequest.First().reportingPeriod?.beginDate ?? DateTime.MinValue,
                    reportTo    = parameters.logisticsInventoryReportRequest.First().reportingPeriod?.endDate ?? DateTime.Now;

            // return value
            LogisticsInventoryReportType report = new LogisticsInventoryReportType()
            {
                creationDateTime   = DateTime.Now,
                documentStatusCode = DocumentStatusEnumerationType.ORIGINAL,
                documentActionCode = DocumentActionEnumerationType.CHANGE_BY_REFRESH,
                logisticsInventoryReportIdentification = new Ecom_EntityIdentificationType()
                {
                    entityIdentification = BitConverter.ToInt64(Guid.NewGuid().ToByteArray(), 0).ToString("X")
                },
                structureTypeCode = new StructureTypeCodeType()
                {
                    Value = "LOCATION_BY_ITEM"
                },
                documentActionCodeSpecified = true
            };

            var locationStockStatuses = new List <LogisticsInventoryReportInventoryLocationType>();

            // Next, we want to know which facilities for which we're getting the inventory report
            List <Place> filterPlaces = null;

            if (parameters.logisticsInventoryReportRequest.First().logisticsInventoryRequestLocation != null &&
                parameters.logisticsInventoryReportRequest.First().logisticsInventoryRequestLocation.Length > 0)
            {
                foreach (var filter in parameters.logisticsInventoryReportRequest.First().logisticsInventoryRequestLocation)
                {
                    int tc    = 0;
                    var id    = filter.inventoryLocation.gln ?? filter.inventoryLocation.additionalPartyIdentification?.FirstOrDefault()?.Value;
                    var place = this.m_placeRepository.Find(o => o.Identifiers.Any(i => i.Value == id), 0, 1, out tc).FirstOrDefault();
                    if (place == null)
                    {
                        throw new FileNotFoundException($"Place {filter.inventoryLocation.gln} not found");
                    }
                    if (filterPlaces == null)
                    {
                        filterPlaces = new List <Place>()
                        {
                            place
                        }
                    }
                    ;
                    else
                    {
                        filterPlaces.Add(place);
                    }
                }
            }
            else
            {
                filterPlaces = this.m_placeRepository.Find(o => o.ClassConceptKey == EntityClassKeys.ServiceDeliveryLocation).ToList();
            }

            // Get the GLN AA data
            var oidService = ApplicationContext.Current.GetService <IOidRegistrarService>();
            var gln        = oidService.GetOid("GLN");
            var gtin       = oidService.GetOid("GTIN");

            if (gln == null || gln.Oid == null)
            {
                throw new InvalidOperationException("GLN configuration must carry OID and be named GLN in repository");
            }
            if (gtin == null || gtin.Oid == null)
            {
                throw new InvalidOperationException("GTIN configuration must carry OID and be named GTIN in repository");
            }

            var masterAuthContext = AuthenticationContext.Current;

            // Create the inventory report
            filterPlaces.AsParallel().ForAll(place =>
            {
                try
                {
                    AuthenticationContext.Current = masterAuthContext;

                    var locationStockStatus = new LogisticsInventoryReportInventoryLocationType();
                    lock (locationStockStatuses)
                        locationStockStatuses.Add(locationStockStatus);

                    // TODO: Store the GLN configuration domain name
                    locationStockStatus.inventoryLocation = this.m_gs1Util.CreateLocation(place);

                    var tradeItemStatuses = new List <TradeItemInventoryStatusType>();

                    // What are the relationships of held entities
                    foreach (var rel in place.Relationships.Where(o => o.RelationshipTypeKey == EntityRelationshipTypeKeys.OwnedEntity))
                    {
                        if (!(rel.TargetEntity is ManufacturedMaterial))
                        {
                            var matl = this.m_materialRepository.GetManufacturedMaterial(rel.TargetEntityKey.Value, Guid.Empty);
                            if (matl == null)
                            {
                                Trace.TraceWarning("It looks like {0} owns {1} but {1} is not a mmat!?!?!", place.Key, rel.TargetEntityKey);
                                continue;
                            }
                            else
                            {
                                rel.TargetEntity = matl;
                            }
                        }
                        var mmat = rel.TargetEntity as ManufacturedMaterial;
                        if (!(mmat is ManufacturedMaterial))
                        {
                            continue;
                        }

                        var mat = this.m_materialRepository.FindMaterial(o => o.Relationships.Where(r => r.RelationshipType.Mnemonic == "Instance").Any(r => r.TargetEntity.Key == mmat.Key)).FirstOrDefault();

                        decimal balanceOH = rel.Quantity ?? 0;

                        // get the adjustments the adjustment acts are allocations and transfers
                        var adjustments = this.m_stockService.FindAdjustments(mmat.Key.Value, place.Key.Value, reportFrom, reportTo);

                        // We want to roll back to the start time and re-calc balance oh at time?
                        if (reportTo.Value.Date < DateTime.Now.Date)
                        {
                            var prevAdjustments = this.m_stockService.FindAdjustments(mmat.Key.Value, place.Key.Value, reportTo, DateTime.Now);
                            balanceOH          -= (decimal)prevAdjustments.Sum(o => o.Participations.FirstOrDefault(p => p.ParticipationRoleKey == ActParticipationKey.Consumable)?.Quantity);
                        }

                        ReferenceTerm cvx = null;
                        if (mat.TypeConceptKey.HasValue)
                        {
                            cvx = ApplicationContext.Current.GetService <IConceptRepositoryService>().GetConceptReferenceTerm(mat.TypeConceptKey.Value, "CVX");
                        }

                        var typeItemCode = new ItemTypeCodeType()
                        {
                            Value           = cvx?.Mnemonic ?? mmat.TypeConcept?.Mnemonic ?? mat.Key.Value.ToString(),
                            codeListVersion = cvx?.LoadProperty <CodeSystem>("CodeSystem")?.Authority ?? "OpenIZ-MaterialType"
                        };

                        // First we need the GTIN for on-hand balance
                        tradeItemStatuses.Add(new TradeItemInventoryStatusType()
                        {
                            gtin         = mmat.Identifiers.FirstOrDefault(o => o.Authority.DomainName == "GTIN")?.Value,
                            itemTypeCode = typeItemCode,
                            additionalTradeItemIdentification = mmat.Identifiers.Where(o => o.Authority.DomainName != "GTIN").Select(o => new AdditionalTradeItemIdentificationType()
                            {
                                additionalTradeItemIdentificationTypeCode = o.Authority.DomainName,
                                Value = o.Value
                            }).ToArray(),
                            tradeItemDescription = mmat.Names.Select(o => new Description200Type()
                            {
                                Value = o.Component.FirstOrDefault()?.Value
                            }).FirstOrDefault(),
                            tradeItemClassification = new TradeItemClassificationType()
                            {
                                additionalTradeItemClassificationCode = mat.Identifiers.Where(o => o.Authority.Oid != gtin.Oid).Select(o => new AdditionalTradeItemClassificationCodeType()
                                {
                                    codeListVersion = o.Authority.DomainName,
                                    Value           = o.Value
                                }).ToArray()
                            },
                            inventoryDateTime        = DateTime.Now,
                            inventoryDispositionCode = new InventoryDispositionCodeType()
                            {
                                Value = "ON_HAND"
                            },
                            transactionalItemData = new TransactionalItemDataType[]
                            {
                                new TransactionalItemDataType()
                                {
                                    tradeItemQuantity = new QuantityType()
                                    {
                                        measurementUnitCode = (mmat.QuantityConcept ?? mat?.QuantityConcept)?.ReferenceTerms.Select(o => new AdditionalLogisticUnitIdentificationType()
                                        {
                                            additionalLogisticUnitIdentificationTypeCode = o.ReferenceTerm.CodeSystem.Name,
                                            Value = o.ReferenceTerm.Mnemonic
                                        }).FirstOrDefault()?.Value,
                                        Value = balanceOH
                                    },
                                    batchNumber                 = mmat.LotNumber,
                                    itemExpirationDate          = mmat.ExpiryDate.Value,
                                    itemExpirationDateSpecified = true
                                }
                            }
                        });


                        foreach (var adjgrp in adjustments.GroupBy(o => o.ReasonConceptKey))
                        {
                            var reasonConcept = ApplicationContext.Current.GetService <IConceptRepositoryService>().GetConceptReferenceTerm(adjgrp.Key.Value, "GS1_STOCK_STATUS")?.Mnemonic;
                            if (reasonConcept == null)
                            {
                                reasonConcept = (ApplicationContext.Current.GetService <IConceptRepositoryService>().GetConcept(adjgrp.Key.Value, Guid.Empty) as Concept)?.Mnemonic;
                            }

                            // Broken vials?
                            tradeItemStatuses.Add(new TradeItemInventoryStatusType()
                            {
                                gtin         = mmat.Identifiers.FirstOrDefault(o => o.Authority.DomainName == "GTIN")?.Value,
                                itemTypeCode = typeItemCode,
                                additionalTradeItemIdentification = mmat.Identifiers.Where(o => o.Authority.DomainName != "GTIN").Select(o => new AdditionalTradeItemIdentificationType()
                                {
                                    additionalTradeItemIdentificationTypeCode = o.Authority.DomainName,
                                    Value = o.Value
                                }).ToArray(),
                                tradeItemClassification = new TradeItemClassificationType()
                                {
                                    additionalTradeItemClassificationCode = mat.Identifiers.Where(o => o.Authority.Oid != gtin.Oid).Select(o => new AdditionalTradeItemClassificationCodeType()
                                    {
                                        codeListVersion = o.Authority.DomainName,
                                        Value           = o.Value
                                    }).ToArray()
                                },
                                tradeItemDescription = mmat.Names.Select(o => new Description200Type()
                                {
                                    Value = o.Component.FirstOrDefault()?.Value
                                }).FirstOrDefault(),
                                inventoryDateTime        = DateTime.Now,
                                inventoryDispositionCode = new InventoryDispositionCodeType()
                                {
                                    Value = reasonConcept
                                },
                                transactionalItemData = new TransactionalItemDataType[]
                                {
                                    new TransactionalItemDataType()
                                    {
                                        tradeItemQuantity = new QuantityType()
                                        {
                                            measurementUnitCode = (mmat.QuantityConcept ?? mat?.QuantityConcept)?.ReferenceTerms.Select(o => new AdditionalLogisticUnitIdentificationType()
                                            {
                                                additionalLogisticUnitIdentificationTypeCode = o.ReferenceTerm.CodeSystem.Name,
                                                Value = o.ReferenceTerm.Mnemonic
                                            }).FirstOrDefault()?.Value,
                                            Value = Math.Abs(adjgrp.Sum(o => o.Participations.First(p => p.ParticipationRoleKey == ActParticipationKey.Consumable && p.PlayerEntityKey == mmat.Key).Quantity.Value))
                                        },
                                        batchNumber                 = mmat.LotNumber,
                                        itemExpirationDate          = mmat.ExpiryDate.Value,
                                        itemExpirationDateSpecified = true
                                    }
                                }
                            });
                        }
                    }

                    // Reduce
                    locationStockStatus.tradeItemInventoryStatus = tradeItemStatuses.ToArray();
                }
                catch (Exception e)
                {
                    traceSource.TraceError("Error fetching stock data : {0}", e);
                }
                // TODO: Reduce and Group by GTIN
            });

            report.logisticsInventoryReportInventoryLocation = locationStockStatuses.ToArray();
            retVal.logisticsInventoryReport = new LogisticsInventoryReportType[] { report };
            return(retVal);
        }