Tworzenie receptury produktu składającego się z półproduktów i surowców

0

Witam.
Mam pewną zagwozdkę, którą nie wiem jak rozwiązać dobrze. Próbowałem while, rekurencji, ale nie potrafię za bardzo wrócić do "głównego" produktu, albo nie tworzy mi wszystkiego.

Ogólnie to potrzebuje założyć kartotekę w systemie ERP dla tego produktu z uwzględnieniem półproduktów, które mogą być zagnieżdżane w nieskończoność i mieszane z surowcami. Problem polega na tym, że muszę zacząć "od końca" żebym mógł założyć kartotekę głównego produktu. Gdzie w 99% surowce są, więc z kartotekami surowca problemu nie ma.

var mainProduct = await _optimesRepository.GetProductByObjectNumber(index); // produkt końcowy
var mainProductResources = await _optimesRepository.GetProductResourcesByObjectNumber(index); // jego składniki, które są półproduktami i/lub surowcami

Jeśli zrobię while to musze przelecieć w pętli po wszystkich. Chyba, że źle robię tego while'a. Przy takim rozwiązaniu productResources będzie ostatnim półproduktem, a reszta się nie doda.

var productResources = mainProductResources.Where(x => x.EntityType == "Product").ToList();

while (productResources.Any())
{
  foreach (var productResource in productResources)
  {

  }
}

Rekurencja też tutaj nie pomaga, ponieważ, tak samo jak w while, pomijam resztę obiektów.

Tak to wygląda przykładowy produkt w bazie
Zrzut ekranu 2024-02-25 100517.png

Niebieski ma pomarańczowe składniki jako półprodukt, a zielone to są składniki pierwszego półproduktu ze screena. Nie mogę założyć, że zawsze będzie taki schemat, muszę założyć, że tych "schodków" z półproduktami będzie wiecej (głębiej) i mogą być też składniki pomieszane, na przykład: półprodukty + surowce -> półprodukty -> surowce

W ERP to są receptury, tworzę sobie towar złożony i do niego przypisuje recepture z jego składnikami, ale żeby przypisać składnik, który jest półproduktem muszę najpierw założyć kartotekę tego półproduktu wraz z jego recepturą i składnikami.

Aktualnie stanąłem na wersji ze stworzeniem listy wszytkiego - produktów, półproduktów i surowców i wtedy poprzez GroupBy(x=>x.ProductCode) wyciągnąłbym pogrupowane produktu i półprodukty wraz z surowcami 🤔

0

Jaki tu jest konkretnie problem bo nie da się tego zrozumieć co napisałeś. Nie zaciąga ci wszystkich enetity do repo czy może coś innego?

0

Chodzi o to, żeby najpierw sprawdzić z jakich produktów/surowców składa się główny produkt i potem dodawać surowce/produkty zaczynając od tych najgłębszych?

internal class Program
{
    //Przygotowanie testowych danych
    public static List<ProductOrResource> Products { get; } = new List<ProductOrResource>()
    {
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = null, Code = "1" }, //Główny produkt
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "1", Code = "1.1" }, //Podprodukt
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "1", Code = "1.2" }, //Podprodukt
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "1", Code = "1.3" }, //Podprodukt
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "1.1", Code = "1.1.1" }, //Podprodukt podproduktu 1.1
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "1.1", Code = "1.1.2" }, //Podprodukt podproduktu 1.1
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "1.1", Code = "1.1.3" }, //Podprodukt podproduktu 1.1
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "1.2", Code = "1.2.1" }, //Podprodukt podproduktu 1.2
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "1.2", Code = "1.2.2" }, //Podprodukt podproduktu 1.2
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "1.3", Code = "1.3.1" }, //Podprodukt podproduktu 1.3
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "1.1.1", Code = "1.1.1.1" }, //Podprodukt podproduktu 1.1.1
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "1.1.1", Code = "1.1.1.2" }, //Podprodukt podproduktu 1.1.1
        new() { Entity = ProductOrResource.EntityType.Resource, ParentProductCode = "1.1.1", Code = "1.1.1.3" } //Surowiec podproduktu 1.1.1
    };

    static void Main(string[] args)
    {
        AddProduct(Products[0]);
        Console.ReadKey();
    }

    public static void AddProduct(ProductOrResource product)
    {
        //Wyciąganie listy podproduktów dla produktu
        List<ProductOrResource> subproducts = GetSubproductsForProduct(product);
        Console.WriteLine("Produkt: " + product.Code + " Podprodukty: " + string.Join(", ", subproducts.Select(x => x.Code)));

        foreach (ProductOrResource subproduct in subproducts)
        {
            AddProduct(subproduct);
        }

        //Tu napisać operacje dodawania produktu / surowca
        Console.WriteLine("Dodanie produktu: " + product.Code);
    }

    public static List<ProductOrResource> GetSubproductsForProduct(ProductOrResource product)
    {
        return Products.Where(x => x.ParentProductCode == product.Code).ToList();
    }

    public class ProductOrResource
    {
        public enum EntityType { Product, Resource }
        public string Code { get; set; }
        public string? ParentProductCode { get; set; }
        public EntityType Entity { get; set; }            
    }
}
0

struktury z wskaźnikamia potrzebujesz potworzyć?

0

@bagietMajster Nie wiem jak jaśniej mogę to jeszcze opisać. Nie chodzi o zaciąganie z repo. Chodzi o tworzenie, w systemie ERP, kartotek produktów ze składnikami, które też są produktem, które tez mają składniki itd...

@AbcDefGhi Jakby to było tylko tak jak w przykładzie to owszem już dawno bym miał to zrobione, ale tak nie jest. Założyłeś, że może być tylko jedna gałąź półproduktów, a tego może być więcej i pomieszane z surowcami.

Rekurencją przy pierwszej iteracji wyjdzie ci z tej pętli i nie doda wszystkich subproducts

foreach (ProductOrResource subproduct in subproducts)
{
  AddProduct(subproduct);
}

Przygotowałeś sobie już wcześniej Products, a ja takiej listy nie mam.

Ciężko to dokładnie opisać. Klient zajmuje się obróbką stali. Żeby wyprodukować gotowy produkt (niebieski ze screena) to potrzebuje najpierw wyprodukować wszystkie półprodukty (pomarańczowe). Aby zrobił każdy półprodukt z osobna trzeba mieć na to surowce i ten pierwszy z listy pomarańczowych ma surowce w sekcji na zielono, każdy kolejny ma swoje inne surowce, lub takie same, lub podobne.

Głównym problemem jest obsługa głębszych zagnieżdżeń niż na przykładzie ze screena oraz mieszanie półproduktów z surowcami. W tym przykładzie półprodukt jest tworzony z towarów, które są surowcami, ale może być kolejnym półproduktem. Nie mogę założyć, że to zawsze będzie tak jak w przykładzie i muszę pójść dwa kroki dalej i z tymi "krokami dalej" mam problem, aby to dobrze obsłużyć.

Jeśli nie stworze odpowiednio tych wszystkich kartotek to nie zrobi się zamówienie do systemie ERP i nie dojdzie do realizacji.

0
AdamWox napisał(a):

@AbcDefGhi Jakby to było tylko tak jak w przykładzie to owszem już dawno bym miał to zrobione, ale tak nie jest. Założyłeś, że może być tylko jedna gałąź półproduktów, a tego może być więcej i pomieszane z surowcami.

Rekurencją przy pierwszej iteracji wyjdzie ci z tej pętli i nie doda wszystkich subproducts

foreach (ProductOrResource subproduct in subproducts)
{
  AddProduct(subproduct);
}

Ta rekurencja przelatuje po wszystkich elementach i gałęziach które są ze sobą powiązane.
Wypisze niebieski element, wszystkie pomaranczowe dla niebieskiego i wszystkie zielone dla wszytkich pomarańczowych i zadziała dla dowolnej ilości zagnieżdżeń.
Wsadziłem surowce i produkty do jednej klasy bo oba obiekty maja swój kod i kod produktu w którym są używane więc pod tym względem są takie same. Ty możesz to rozbić na 2 klasy / tabele.

AdamWox napisał(a):

Przygotowałeś sobie już wcześniej Products, a ja takiej listy nie mam.

Tutaj nie do końca rozumiem. Nie jesteś w stanie stworzyć jakimiś zapytaniami takiej listy połączeń? Jeśli nie to skąd wiesz z czego składa się dany produkt czy podprodukt?

0

Ja nie dostaje takiej przykładowej listy jak stworzyłeś. Ja dostaje ID zamówienia, z którego wyciągam pozycje i na podstawie tych pozycji odpytuje bazę produkcyjną o dane do stworzenia kartotek (produktów, półproduktów, surowców). Ja nie mam takiego "drzewka", bo ja na wejściu nie wiem jeszcze co z czym jest powiązane i jak dużo jest zagnieżdzeń.

2

Czyli masz przykładowe zamówienie.
IdZamowienia = 5;

Pytasz bazę o wszystkie pozycje z zamówienia gdzie Id = 5 i dostajesz w odpowiedzi na przykład 3 produkty.
Produkt1
Produkt2
Produkt3

Nastepnie dla kazdego z tych produktów pytasz baze z czego każdy z nich się składa. Np:
Produkt1 składa się z 1 surowca i 2 półproduktów.
Produkt2 składa się z 2 surowców i 10 półproduktów
Produkt3 składa się z 15 surowców.

I dla każdego półproduktu pytasz dalej baze o jego skład, a jeśli to surowiec to już nie pytasz, aż do momentu kiedy nie będzie żadnego półproduktu do sprawdzenia.

Tak to wygląda czy inaczej?

0

Dokładnie tak to wygląda. I problemem jest to, że, na przykład, Produkt1, ma 2 półprodukty, których kartoteki muszę utworzyć najpierw żebym mógł utworzyć kartotekę Produkt1, a te półprodukty zaś mogę mieć jakies półprodukty. Na tę chwilę, aż takiego głębokiego zagnieżdżania nie ma, ale wole się przygotować na najgorszę.

Ogólnie rzecz biorąc żeby stworzyć twój przykładowy Produkt1 muszę najpierw dojść na sam koniec tego "drzewka" półproduktów żeby wrócić do "głównego" produktu i stworzyć dla niego kartotekę.

1

To wracamy do kodu powyżej tylko, że wywołujemy go dla każdego produktu z zamówienia.

internal class Program
{
    //Przygotowanie testowych danych
    //Te dane sa w bazie danych
    public static List<ProductOrResource> ProductsDatabase { get; } = new List<ProductOrResource>()
    {
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "1", Code = "1.1" }, //Podprodukt
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "1", Code = "1.2" }, //Podprodukt
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "1", Code = "1.3" }, //Podprodukt
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "1.1", Code = "1.1.1" }, //Podprodukt podproduktu 1.1
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "1.1", Code = "1.1.2" }, //Podprodukt podproduktu 1.1
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "1.1", Code = "1.1.3" }, //Podprodukt podproduktu 1.1
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "1.2", Code = "1.2.1" }, //Podprodukt podproduktu 1.2
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "1.2", Code = "1.2.2" }, //Podprodukt podproduktu 1.2
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "1.3", Code = "1.3.1" }, //Podprodukt podproduktu 1.3
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "1.1.1", Code = "1.1.1.1" }, //Podprodukt podproduktu 1.1.1
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "1.1.1", Code = "1.1.1.2" }, //Podprodukt podproduktu 1.1.1
        new() { Entity = ProductOrResource.EntityType.Resource, ParentProductCode = "1.1.1", Code = "1.1.1.3" }, //Surowiec podproduktu 1.1.1
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "2", Code = "2.1" }, //Podprodukt
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "2", Code = "2.2" }, //Podprodukt
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "2", Code = "2.3" }, //Podprodukt
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "2.1", Code = "2.1.1" }, //Podprodukt podproduktu 2.1
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "2.1", Code = "2.1.2" }, //Podprodukt podproduktu 2.1
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "2.1", Code = "2.1.3" }, //Podprodukt podproduktu 2.1
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "2.2", Code = "2.2.1" }, //Podprodukt podproduktu 2.2
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "2.2", Code = "2.2.2" }, //Podprodukt podproduktu 2.2
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "2.3", Code = "2.3.1" }, //Podprodukt podproduktu 2.3
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "2.1.1", Code = "2.1.1.1" }, //Podprodukt podproduktu 2.1.1
        new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = "2.1.1", Code = "2.1.1.2" }, //Podprodukt podproduktu 2.1.1
        new() { Entity = ProductOrResource.EntityType.Resource, ParentProductCode = "2.1.1", Code = "2.1.1.3" } //Surowiec podproduktu 2.1.1
    };

    static void Main(string[] args)
    {
        Order order = new();
        order.OrderId = 5;
        HandleOrder(order);
        Console.ReadKey();
    }

    public static void HandleOrder(Order order)
    {
        //Zamienić to przypisanie na probranie produktów z bazy danych dla danego zamówienia
        Console.WriteLine("Pobieranie produktów dla zamówienia ID: " + order.OrderId);
        List<ProductOrResource> products = new()
        {
            new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = null, Code = "1" },
            new() { Entity = ProductOrResource.EntityType.Product, ParentProductCode = null, Code = "2" }
        };

        Console.WriteLine("Produkty zawarte w zamówieniu to: " + string.Join(", ", products.Select(x => x.Code)));

        foreach (ProductOrResource product in products)
        {
            AddProduct(product);
        }
    }

    public static void AddProduct(ProductOrResource product)
    {
        //Wyciąganie listy podproduktów dla produktu
        Console.WriteLine("Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: " + product.Code);
        List<ProductOrResource> subproducts = GetSubproductsForProduct(product); //Tu pobrac liste subproduktów i zasobów z bazy
        Console.WriteLine("Produkt / surowiec: " + product.Code + " Półprodukty / surowce: " + string.Join(", ", subproducts.Select(x => x.Code)));

        foreach (ProductOrResource subproduct in subproducts)
        {
            AddProduct(subproduct);
        }

        //Tu stworzyć kartotekę dla produktu / zasobu i zapisać w bazie
        Console.WriteLine("Dodanie produktu / surowca " + product.Code +" do bazy");
    }

    public static List<ProductOrResource> GetSubproductsForProduct(ProductOrResource product)
    {
        return ProductsDatabase.Where(x => x.ParentProductCode == product.Code).ToList();
    }

    public class Order
    {
        public int OrderId { get; set; }
        
    }

    public class ProductOrResource
    {
        public enum EntityType { Product, Resource }
        public string Code { get; set; }
        public string? ParentProductCode { get; set; }
        public EntityType Entity { get; set; }            
    }
}

Tam gdzie są komentarze trzeba zamienić na pobieranie danych z bazy i powinno śmigać.

Output:
Pobieranie produktów dla zamówienia ID: 5
Produkty zawarte w zamówieniu to: 1, 2
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 1
Produkt / surowiec: 1 Półprodukty / surowce: 1.1, 1.2, 1.3
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 1.1
Produkt / surowiec: 1.1 Półprodukty / surowce: 1.1.1, 1.1.2, 1.1.3
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 1.1.1
Produkt / surowiec: 1.1.1 Półprodukty / surowce: 1.1.1.1, 1.1.1.2, 1.1.1.3
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 1.1.1.1
Produkt / surowiec: 1.1.1.1 Półprodukty / surowce:
Dodanie produktu / surowca 1.1.1.1 do bazy
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 1.1.1.2
Produkt / surowiec: 1.1.1.2 Półprodukty / surowce:
Dodanie produktu / surowca 1.1.1.2 do bazy
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 1.1.1.3
Produkt / surowiec: 1.1.1.3 Półprodukty / surowce:
Dodanie produktu / surowca 1.1.1.3 do bazy
Dodanie produktu / surowca 1.1.1 do bazy
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 1.1.2
Produkt / surowiec: 1.1.2 Półprodukty / surowce:
Dodanie produktu / surowca 1.1.2 do bazy
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 1.1.3
Produkt / surowiec: 1.1.3 Półprodukty / surowce:
Dodanie produktu / surowca 1.1.3 do bazy
Dodanie produktu / surowca 1.1 do bazy
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 1.2
Produkt / surowiec: 1.2 Półprodukty / surowce: 1.2.1, 1.2.2
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 1.2.1
Produkt / surowiec: 1.2.1 Półprodukty / surowce:
Dodanie produktu / surowca 1.2.1 do bazy
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 1.2.2
Produkt / surowiec: 1.2.2 Półprodukty / surowce:
Dodanie produktu / surowca 1.2.2 do bazy
Dodanie produktu / surowca 1.2 do bazy
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 1.3
Produkt / surowiec: 1.3 Półprodukty / surowce: 1.3.1
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 1.3.1
Produkt / surowiec: 1.3.1 Półprodukty / surowce:
Dodanie produktu / surowca 1.3.1 do bazy
Dodanie produktu / surowca 1.3 do bazy
Dodanie produktu / surowca 1 do bazy
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 2
Produkt / surowiec: 2 Półprodukty / surowce: 2.1, 2.2, 2.3
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 2.1
Produkt / surowiec: 2.1 Półprodukty / surowce: 2.1.1, 2.1.2, 2.1.3
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 2.1.1
Produkt / surowiec: 2.1.1 Półprodukty / surowce: 2.1.1.1, 2.1.1.2, 2.1.1.3
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 2.1.1.1
Produkt / surowiec: 2.1.1.1 Półprodukty / surowce:
Dodanie produktu / surowca 2.1.1.1 do bazy
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 2.1.1.2
Produkt / surowiec: 2.1.1.2 Półprodukty / surowce:
Dodanie produktu / surowca 2.1.1.2 do bazy
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 2.1.1.3
Produkt / surowiec: 2.1.1.3 Półprodukty / surowce:
Dodanie produktu / surowca 2.1.1.3 do bazy
Dodanie produktu / surowca 2.1.1 do bazy
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 2.1.2
Produkt / surowiec: 2.1.2 Półprodukty / surowce:
Dodanie produktu / surowca 2.1.2 do bazy
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 2.1.3
Produkt / surowiec: 2.1.3 Półprodukty / surowce:
Dodanie produktu / surowca 2.1.3 do bazy
Dodanie produktu / surowca 2.1 do bazy
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 2.2
Produkt / surowiec: 2.2 Półprodukty / surowce: 2.2.1, 2.2.2
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 2.2.1
Produkt / surowiec: 2.2.1 Półprodukty / surowce:
Dodanie produktu / surowca 2.2.1 do bazy
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 2.2.2
Produkt / surowiec: 2.2.2 Półprodukty / surowce:
Dodanie produktu / surowca 2.2.2 do bazy
Dodanie produktu / surowca 2.2 do bazy
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 2.3
Produkt / surowiec: 2.3 Półprodukty / surowce: 2.3.1
Pobieranie informacji z bazy o półproduktach / surowcach dla produktu: 2.3.1
Produkt / surowiec: 2.3.1 Półprodukty / surowce:
Dodanie produktu / surowca 2.3.1 do bazy
Dodanie produktu / surowca 2.3 do bazy
Dodanie produktu / surowca 2 do bazy

1

właśnie tez nie do końca rozumiem opis problemu, bo jeżeli chodzi o założenie zamówienia/zlecenia na produkt na podstawie istniejącej definicji artykułu/produktu to rozwiązanie jest powyżej, (tam warto jeszcze uwzględnić ilości i sprawdzanie czy nie ma czegoś zagnieżdżonego na stanie magazynu)

ale jeżeli chodzi o założenie definicji (jeżeli kartoteka jest definicją artykułu) w ERP, to tutaj mam główne pytanie skąd się bierze informacja co z czego się składa?

zakładając ze ta informacja jest u użytkownika który ma to wyklinać to w dalszym ciągu są dwie możliwości zbudowania definicji takiego artykułu w zależności od tego czy wszystkie indexy zagnieżdżone do samego dołu w całej definicji sa już założone w ERP czy nie (założone - to mam na myśli definicję tylko kodu artykułu/index z cechą czy jest to materiał prosty czy złożony)
i jeżeli wszystkie indexy już są, to można budować definicję artykułu od góry i schodząc w dół dodawać kolejne receptury dla kolejnych skladnikow zlozonych.
ale jeżeli indexów nie ma i dopiero trzeba je pozakładać to tylko i wyłączenie budujemy od dołu definicje kolejnych artykułów tylko ze wtedy nie ma po czym schodzić w dół do najgłębszej definicji bo nie ma nigdzie zdefiniowanej struktury BoM'u

0

Jakie ma znaczenie skąd się bierze informacja do założenia kartoteki? Dane na temat kartotek pochodzą z systemu produkcyjnego, w którym nie ma fakturowania. Takie zamówienie na produkcje muszę przerzucić do systemu ERP jako proforma w celu opłacenia ewentualnej zaliczki, ale nie mam kartotek. Cała definicja "drzewka" do receptur pochodzi właśnie z tego systemu produkcyjnego. Nie wiem jak jeszcze mógłbym to mądrzej wytłumaczyć. Nie ma indeksów w ERP, post jest właśnie na temat założenia tych indeksów/kartotek/definicji, nazywać możemy sobie to różnie.

Produkt może być składnikiem innego produktu i to trzeba uwzględnić na kartotece. Mam opisywać jak działają receptury w Comarch Optima?

PS.
Słowo produkt w tym poście nie jest zwykłym towarem (prostym), a towarem (złożonym), który trzeba skompletować i taki towar może mieć inne towary w swojej "recepturze", które też najpierw trzeba skompletować, aby skompletować ten "główny". Post nie jest na temat kompletacji, ponieważ to się dzieje na produkcji. Post jest na temat założenia w odpowiednim formacie kartoteki takiego produktu z uwzględnieniem wszystkich półproduktów i surowców.

0

Nie wiem czy ja to zrozumiałem dobrze ale musiałbyś posiadać drzewko produktów i z czego złożony jest ten produkt, w postaci takiego drzewa pewna hierarchia i w końcu musiało by dojść do produktu z którego nic się już więcej nic nie składa np, farba składa się z tego i tego i tego później z czego się to składa a później z czego składają się składniki. Bo jak tak zrobisz tą pętle to ci się nigdy nie skończą i będzie się tak wywoływało bez końca. Kompilator czy to coś będzie ci się odzywać z błędem bo to się tyle razy wywoła dla danego produktu na pewno bardzo dużo razy. Jakiś tam poziom zagnieżdżenia w tej tablicy w bazie i tabeli musiało by to być. Jeżeli w tych składnikach jest węgiel to węgiel jest wydobywany w ziemi nikt go nie wyprodukował to jest wydobycie. Na węglach się nie znam.

0

Jeszcze tak na szybko dodam, że w drzewku BoMów/Receptur/List materiałowych jest główna zasada że produkt nie może zawierać samego siebie ani w swoim BoMie ani w żadnym zagnieżdżonym w sobie bomie. Każdy interfejst ERP tego pilnuje ale jeżeli się to robi 'bezpośrednio' to na to trzeba uważać.

0

No to czy tobie się nie wróci to np. że do produktu nie jest dodany ten produkt pierwszego rzędu bo to się będzie zapętlać.

0

Mówimy o produkcji z życia wziętej. Jeśli wpadnie taki przypadek, że jest składnikiem dla samego siebie to to jest błąd użytkownika, który taką recepturę stworzył. Nie wiem czy system produkcyjny ma jakąś walidacje na takie rzeczy. Chyba pętle i rekurencje nie są tutaj najlepszym rozwiązaniem. Jeśli stworze listę totalnie wszystkiego "na płasko", a potem pogrupuje po indeksie parenta/produktu to jeśli będą zagnieżdżenia do siebie samego to kartoteka stworzy się najwyżej dwa razy, ale... Samo ERP ma już zabezpieczenie, ponieważ w Optimie kod towaru to unikalny indeks kartoteki, który nie może się powtórzyć, więc walnie błędem gdy drugi raz będzie chciał stworzyć taki sam produkt.

Zrobiłem metodę, która wrzuca wszystko do jednego worka, płasko. W parametrze przekazuje dane o produkcie końcowym, ostatecznym z systemu produkcyjnego.

        async Task<List<OptimesResourceData>> _getAllResources(OptimesProductData product)
        {
            List<OptimesResourceData> resources = new List<OptimesResourceData>();
            var productResources = await _optimesRepository.GetProductResourcesByObjectNumber(product.Code);

            while (productResources.Any())
            {
                List<OptimesResourceData> currentResources = new List<OptimesResourceData>();
                foreach(var resource in productResources )
                {
                    if (resource.EntityType == "Product")
                    {
                        var r = await _optimesRepository.GetProductResourcesByObjectNumber(resource.ResourceCode);
                        currentResources.AddRange(r);
                    }
                    else
                        currentResources.Add(resource);
                }

                resources.AddRange(currentResources);
                productResources = new List<OptimesResourceData>(currentResources.Where(x=>x.EntityType == "Product"));
            }

            return resources;
        }

Następnie grupuję po ProductCode, który na tej stworzonej, płaskiej liście powtarza się dla każdego składnika/półproduktu, jako taki "parent index". Pomijam ten końcowy, ostateczny, jego tworze osobno na samym końcu jak wszystko co pośrednie zostanie stworzone.

            var mainProduct = await _optimesRepository.GetProductByObjectNumber(index);
            if (mainProduct is null)
                return;

            var mainProductResources = await _optimesRepository.GetProductResourcesByObjectNumber(index);

            var resources = await _getAllResources(mainProduct);
            var groupedResources = resources.GroupBy(x => x.ProductCode);

            foreach (var resource in groupedResources.Where(x=>x.Key != index))
            {}

Pewnie to jest jakiś overkill, ale chyba działa, bo jeszcze klient nie zgłosił zażaleń.

0

Czy Pan zajmuje się tworzeniem Optimy czy zajmuje się Pan tworzeniem własnego oprogramowania ?

0

To jakiś sarkazm, czy faktycznie pytanie?

0

Dane w bazie != dane w logice, na podstawie płaskiej struktury w bazie możesz utworzyć sobie strukturę drzewiastą. Potem idzesz w głąb drzewa i od końca robisz tworzenie "podzasobów". Przy uzyciu rekurencji sie najmniej najebiesz.

1 użytkowników online, w tym zalogowanych: 0, gości: 1