Kostprijsberekeningsmodellen met > 400 vars

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Toms Diner

Toms Diner

12/10/2017 21:40:55
Quote Anchor link
Vraagje.

Ik ben bezig met het omzetten van een grote excelsheet (+35 tabs) naar een online applicatie. Het gaat om kostprijsberekening in een bepaalde sector. Hiervoor heeft de gebruiker ruim 250 velden zelf in te vullen, waarna er diverse zaken omtrent de kostprijsberekening van een product berekend worden. Denk aan productiemachines, afschrijving, onderhoudskosten, interest, enzovoort.

Zoals vermeld is er een bron: een excel sheet. Deze laat eigenlijk al goed de valkuil zien: je raakt het overzicht kwijt, en voor je het weet zit er een verkeerde celverwijzing in, of wordt de interest per ongeluk over 1 maand afschrijving berekend in plaats van over het gemiddelde uitstaande bedrag.

Ik wil dus een PHP applicatie bouwen -en het gaat nu alleen om het berekendende gedeelte- die volgbaar is, later makkelijk aan te passen/tweaken, en die ook meewerkt aan het bewijzen van de kloppendheid van de berekeningen.

Middels Ajax wordt alle user-input realtime van het formulier gehaald en in de database gestopt. Daarna drukt met op "berekenen", en gaat de berekeningsmodule draaien. Ik heb al bedacht dat in de database voor elk veld (=elke vraag) een naam aanwezig is, zodat bij het uitlezen een grote array ontstaat, zoals bijvoorbeeld:

$a['BenzineprijsPerLiter'] = 1.5319;
$a['MachineXRestwaarde'] = 24000;
$a['MachineYOnderhoudskostenPerMaand'] = 200;

Maar hoewel ik uniformiteit probeer aan te houden (keys beginnen met de naam van het onderwerp/de machine/het product/enzovoort), is het nu al een zootje, en van de 400 geplande variabelen zijn er zeker 150 nog niet in het model ingebouwd. En het zijn nu al 680 regels aan berekeningen....

Helaas hebben vrijwel alle machines en onderwerpen puur eigen velden, er is dus geen makkelijke weg om met een FOREACH ($allmachines AS $currentmachine) te werken. Wel zijn sommige zaken in functies te plaatsen. Zo heb ik alle delingen in een kleine functie ondergebracht, die bij een deling door nul als antwoord nul geeft.. (ipv een deling door nul-error) Echter moeten bij veel berekeningen waardes van alle acht producten mee, waardoor functies veel te veel parameters krijgen. En ook classes werken niet: om van 1 product de opslag van een bepaalde kostensoort te weten, moet je een verdeling over alle producten tegelijk maken. Voortdurend werk je dus met veel door elkaar heen...

Ik loop al enkele dagen te zoeken hoe je om moet gaan met modellen, maar Google denkt nu dat ik een fetish voor badpakken en blond heb, geloof ik.

Bestaan er voor dit soort bouwsels plannen van aanpak (en weet iemand dan trefwoorden)?
Of kun je bewijs van spreke een groot gedeelte van de formules op één of andere manier in de database opslaan, zodat je een heel clean programma houdt?
En de methode die ik nu gebruik ($a['MachineABijvbultijdInSec'] = 120), is dat een handige, of zie ik iets slimmers over het hoofd? (dit levert wel makkelijke var_dumps op!)
 
PHP hulp

PHP hulp

22/11/2024 10:35:04
 
- Ariën  -
Beheerder

- Ariën -

12/10/2017 22:04:43
Quote Anchor link
Je kan je array toch ook splitsen in een multidimensionale array?
De variabele $a slaat als een tang op een drumstel, en zegt niet wat er in zit. Daarom noem ik het maar $data ;-)

Opzetje voor de Vultijd van machine A.
$data['machine']['A']['Vultijd'] = 120

Ik neem aan dat de grootheid als seconden consequent aangehouden wordt, dan is eigenlijk die beschrijving in de key niet meer nodig. Als die data in de database staat, kan je dit prima bij de input vermelden of berekenen.

En voor losse eenheden, kan je dit bijvoorbeeld doen:
$data['Eenheden']['benzine']['literprijs'] = 1.5319;
Gewijzigd op 12/10/2017 22:06:04 door - Ariën -
 
Toms Diner

Toms Diner

12/10/2017 22:29:12
Quote Anchor link
Helaas, diverse variabele kosten zijn bijvoorbeeld de loonkosten per seconde. Maar veel andere kosten zijn per uur (huurkosten bijvoorbeeld) of maand (abonnementen) of ook jaarkosten (interest). Omdat veel fouten in deze hoek zitten in de excel tabel, wordt met opzet in de naam de periodiciteit opgenomen....

En $a is gekozen (ipv $data) omdat het korter is:)

Inderdaad is een multidimensionale array ook mogelijk, maar omdat veel variabelen uniek zijn (niet alle machines hoeven bijgevuld te worden) vond ik in die hoek te weinig voordeel...

Of ik nou

$a['MachineAVultijd']

of

$a['Machine']['A']['Vultijd'] gebruik: daar ga ik denk ik niets op winnen, tenzij er voor alle machines een vultijd zou zijn. Overigens waar dat kan is soms al met een foreach en $a[$currentmachinename . 'Vultijd'] gewerkt. (niet multidimensionaal, maar stiekum toch een beetje).

En weet: het kan ook arrayloos: $machineAVultijd is ook een mogelijkheid, maar ik twijfel of kleinigheidjes in de naamgeving de 680 regels dusdanig in kunnen korten en overzichtelijker maken dat het voordeel biedt.

Ik heb ook al een tijd zitten denken of de formules niet in de database te stoppen zijn. Ik heb zelfs een test gemaakt met een soort tabel als hieronder:

Veldnaam (=var naam die later weer aangeroepen kan worden)
Teller (=hierin stop je alle veldnamen die opgeteld de teller vormen, of een nummer)
Noemer (=hierin stop je alle veldnamen (of een nummer) die opgeteld delen op de complete teller)
Vermenigvuldiger (=de deling hiervoor wordt vermenigvuldigd met dit bedrag of deze veldnamen)
Optellen (= bij de uitkomst van de deling en vermenigvuldiging worden deze velden/dit getal opgeteld)
Aftrekken (=bij de uitkomst van de som tot hiervoor worden deze velden/dit getal afgetrokken)

Rekenvoorbeeld:

Veldnaam: LoonkostenVullenMachineA
Teller: MachineAVultijd
Noemer: 3600
Vermenigvuldiger: LoonkostenVulpersoneelPerUur
Optellen: 0
Aftrekken: 0

(delen door 3600 maakt van secondes uren)

Ik liet deze met een Do While loop draaien, en velden die nog onbekend waren als ze aan de beurt waren werden overgeslagen. Na een aantal ronden zijn dan alle velden bekend, en stopt de lus.

Het programma werd aanzienlijk kleiner, en ik kreeg mooie debug mogelijkheden door een grafische weergave van alle berekeningen naar de browser te sturen. Helaas wordt de tabel totaal onoverzichtelijk, en krijg je ruis doordat formules zonder deling een "teller=1" en "noemer=1" moesten bevatten, net zoals optellen en aftrekken een nul moest bevatten, en bij één tikfout in een naam krijg je geen foutmelding, maar een eeuwigdurende lus. (Hij komt niet meer uit de do..while)

Zijn er geen standaard methodes voor zoiets? Want ik kan me niet voorstellen dat ik de enige eikel ben die hier mee te dealen heeft...
 
Jacco Engel

Jacco Engel

13/10/2017 12:54:08
Quote Anchor link
Mischien geen relevante vraag (en mischien maakt het je leven makkelijker).

Quote:
Helaas, diverse variabele kosten zijn bijvoorbeeld de loonkosten per seconde. Maar veel andere kosten zijn per uur (huurkosten bijvoorbeeld) of maand (abonnementen) of ook jaarkosten (interest).


Is het een optie om alle bedragen terug te rekenen naar de kleinste tijdmaat?

Dus bijvoorbeeld (versimpeld) :
ik heb 2 abonnementen a 10 euro van een MAAND
ik heb 1 keer interest a 120 euro van een JAAR

Dat je dit op codeniveau ombouwt naar :
ik heb 2 abonnementen a 10 euro van een MAAND
ik heb 1 keer interest a 10 euro van een MAAND

Vervolgens kun je dan bijvoorbeeld de volgende Objecten maken:
Kostenpost :
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
<?php
/* Abonnement */
$kostenpost["naam"] = "abonnement";
$kostenpost["prijs"] = 10;
$kostenpost["multiplyer"] = 1;

/* interest*/
$kostenpost["naam"] = "interest";
$kostenpost["prijs"] = 10;
$kostenpost["multiplyer"] = 12;
?>


Als je deze informatie hebt kun je bijvoorbeeld de kosten op basis van looptijd (in jaren) als volgt uitreken :
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
$kostenTotaleLooptijd
= ($kostenpost["prijs"] * $kostenpost["multiplyer"]) * $looptijdInJaren;
?>


Hopelijk heb je beetje beeld van wat ik bedoel. Als je dit doet kun je namelijk wel gewoon met een foreach gaan werken
 
Frank Nietbelangrijk

Frank Nietbelangrijk

13/10/2017 14:23:20
Quote Anchor link
Het klinkt mij als "Ik zou het met een goede Object Oriented structuur geweldig kunnen verbeteren."

IN OOP (Object Oriented Programming) ga je namelijk classes bouwen die allemaal "zelfstandig" hun eigen stukje verantwoordelijkheid hebben in een klein deel van het totaalproces. Bovendien kun je deze classes van elkaar afleiden en zou je dus een "hoofdclass" Machine kunnen hebben die standaard code bevat die je voor ALLE diverse MACHINES zou kunnen gebruiken maar ook kunt aanpassen bij de machines waar dat voor nodig is.

Vervolgens maak je een class MachineX die alle variabelen en code overerft van de class Machine. Deze nieuwe class heeft dan dezelfde functionaliteiten als de hoofdclass maar daarna ga je MachineX uitbreiden met functionaliteiten die speciaal voor MachineX nodig zijn.
Gewijzigd op 13/10/2017 14:25:14 door Frank Nietbelangrijk
 
Toms Diner

Toms Diner

14/10/2017 23:43:08
Quote Anchor link
We gaan een beetje de verkeerde kant op....

Het was niet mijn bedoeling om de discussie de kant van "hoe splits ik de variabelen / arrays uit". Als zie ik dat ik het zelf uitlok met de laatste regel van de openingspost.

Mijn basis is een excelsheet met zo'n 35 tabbladen en 4.700 velden met formules en een kleine 80 macro's. Echter heeft de maker logischerwijze voor veel formules meerdere cellen in gebruik. Met wat ik samen kan nemen zit ik nu op ongeveer 550 formules, en dat is eigenlijk ook nog meer dan nodig is, want er zijn maar 400 variabelen te vullen. En daarvan zijn er 250 door de user opgegeven. Echter zijn er zo'n 150 formules die tussen-berekeningen maken om de andere formules te vereenvoudigen. De laatste 150 variabelen geven de output.

Van classes ben ik afgestapt, omdat dit de samenhang onduidelijker maakt. (Mensen die mij moeten controleren krijgen veel meer werk) Ook kan je dan wel heel veel variabelen global gaan definieren, omdat de machines soms ook eigenschappen van andere machines moeten kunnen zien, en per sectie al gauw 10-30 van de user-invoer velden nodig zijn. Het leidt tot het doorgeven van erg veel variabelen, en erg veel extra regels programma. Om ongeveer dezelfde reden gebruik ik functies ook zeer beperkt, en alleen voor simpele taken. Het gros is dus oldskool "recht toe recht aan".

De reden van dit topic is dat ik me niet aan de indruk kan onttrekken dat de insteek anders kan. Je zou het liefst de formules van de programma-code scheiden, zodat onze huis-economen een makkelijkere controle taak hebben. Ook zou het het aanpassen van de berekeningswijze eenvoudiger moeten maken. Zeg maar MVC waarbij M opgesplitst wordt in Model enerzijds, en code anderzijds. Zoals ik al schreef heb ik zelf zitten testen met het in een database plaatsen van de formules, maar daarbij ging het overzicht ook verloren.

Bestaan er geen libraries om grote hoeveelheden "model" te importeren en verwerken?
 
Ozzie PHP

Ozzie PHP

15/10/2017 01:47:49
Quote Anchor link
Toms Diner op 12/10/2017 22:29:12:
En $a is gekozen (ipv $data) omdat het korter is:)

Ik raad je aan om af te stappen van dat soort gedachtes. Als je ooit je eigen codes moet aanpassen, heb je geen flauw idee meer wat je bedoelde. Tip: gebruik normale namen. Als je die 3 extra letters niet wil typen ... zou ik eens overwegen of programmeren wel bij je past ;-)
 
Rob Doemaarwat

Rob Doemaarwat

15/10/2017 01:57:44
Quote Anchor link
Je weet dat je in Excel cellen ook een naam kunt geven?

Als ik het zo lees lijkt me dit echt een typische "Excel applicatie". Een (of meerdere) tabblad(en) met alle invoervelden, en dan een ander tabblad(en) met het rekenwerk (+ evt macro's). Als je PHP alleen maar als veredelde rekenmachine wilt gebruiken zie ik niet zoveel voordelen.

En als je het in Excel doet snapt elke kantoorpipo het. Ook de huis-econoom.

De huidige aanpak zal niet ideaal zijn (en misschien ook nog wel geoptimaliseerd kunnen worden), maar als je dit in PHP met een HTML+javascript+ajax frontend gaat doen, dan snapt niemand anders het (behalve jij - en als ik het zo lees ligt zelfs dat nog niet 100% vast).

Wel goed voor je baangarantie / slecht voor het bedrijf als jij een keer onder lijn 5 komt.



Toevoeging op 15/10/2017 09:48:36:

Andersom: Ben je niet gewoon op zoek naar extract? Kun je al je parameters direct als variabele aanroepen, ipv steeds $a['...'] te moeten schrijven.
 
Thomas van den Heuvel

Thomas van den Heuvel

15/10/2017 14:49:17
Quote Anchor link
@Toms Diner begrijp ik het goed dat je direct van Excel naar PHP-code wilt? Of heb je deze Excel-sheets al ge-reverse engineered naar een soort van specificatie? Zoniet, is dat wellicht een idee, zodat je daar van uit kunt na gaan denken over een implementatie in PHP. En als dat jou niet direct lukt heb je meteen een soort van documentatie die verwoordt wat er zou moeten gebeuren zodat je niet helemaal vanaf 0 hoeft te beginnen / niet alles opnieuw hoeft uit te leggen.

Als een 1:1 vertaling uit de hand loopt kan een tussenstap misschien wat meer inzicht verschaffen.
 
Frank Nietbelangrijk

Frank Nietbelangrijk

15/10/2017 17:29:02
Quote Anchor link
Mja ik herken het wel enigzins. Uit zo een Excel bestand proberen al die formules over te nemen in je applicatie is een hels karwei. En inderdaad moeilijk om daar structuur aan te geven.

Een idee waar je voor jezelf maar moet bedenken of je er iets mee kan.

Je zou PHP rekenbladen kunnen introduceren. PHP bestanden opgeslagen in een aparte directory waarin enkel rekenwerk gedaan wordt, helemaal los van je web applicatie. In je webapplicatie leg je alleen vast wanneer er welk rekenblad gebruikt moet worden en ben je enkel geïnteresseerd in de uitkomst(en). De huis-economen geef je toegang tot de rekenbladen en je geeft ze een korte introductie PHP.

sheets/calcheet1.php
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
<?php
// sheets/calcheet1.php

$a = ( 11 + 33 / 12 ) + 0.53 ;
$b = $a * $a - 22;
?>


Ergens in je applicatie:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
function calcSheet($sheetName)
{

    include 'sheets/' . $sheetName . '.php';
    
    return get_defined_vars();
}


$results = calcSheet('calcsheet1');

// je applicatie weet nu dat je $a hebben wilt
$variable = 'a';

// ergens in je template...
echo '<p>De uitkomst is: ' . $results[$variable] . '</p>';
?>


Of stel je gebruikt Twig als template-engine:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
<p>De uitkomst is: {{ results.a }}</p>


HET OVERGROTE NADEEL VAN DEZE AANPAK IS NATUURLIJK WEL DAT DE REKENSHEETS GEBRUIKT KUNNEN WORDEN OM JE APPLICATIE TE HACKEN. DUS ZORG DAT ALLEEN ENKELE BEVOEGDEN AAN DE BESTANDEN MOGEN KNOEIEN.

Toevoeging op 15/10/2017 17:43:55:

Edit:

Een zoekopdracht op Google met php calculation parser Levert interessante informatie op. Als daar wat geschikts bij zit kun je misschien bovenstaand idee VEILIG toepassen.
 
Toms Diner

Toms Diner

15/10/2017 20:53:28
Quote Anchor link
Ozzie PHP op 15/10/2017 01:47:49:
Toms Diner op 12/10/2017 22:29:12:
En $a is gekozen (ipv $data) omdat het korter is:)

Ik raad je aan om af te stappen van dat soort gedachtes. Als je ooit je eigen codes moet aanpassen, heb je geen flauw idee meer wat je bedoelde. Tip: gebruik normale namen. Als je die 3 extra letters niet wil typen ... zou ik eens overwegen of programmeren wel bij je past ;-)


Hoewel ik de reactie weinig vind toevoegen, "dwingt" de laatste zin mij toch even tot reageren...

Ik ben bekend met naming conventions en documenteer mijn programma's netjes. Zoals je zou moeten weten, zijn de naming conventions meestal een richtlijn, geen wet.

Mocht jij een wat minder zekere, beginnende programmeur zijn: prima! Gebruik de conventions alsof het een wet is. Als je wat meer ervaring (en misschien ook in teamverband) hebt, zul je zien dat er soms beargumenteerbare redenen zijn om af te wijken van de conventions. De richtlijnen zijn vaak handig en duidelijk, maar soms weegt dit niet op tegen een alternatief.

Dus als je je er zekerder bij voelt: vooral doen. Maar ga niet lopen miepen dat mensen die er anders over denken misschien een ander beroep moeten kiezen. En ik wil dan ook niet één [for ($i=0;...] in jouw programma's tegenkomen!

Overigens is dit het laatste wat ik over de var-namen wil zeggen, want het vervuilt dit topic, en draagt niet bij aan een oplossing.

Rob Doemaarwat op 15/10/2017 01:57:44:
Je weet dat je in Excel cellen ook een naam kunt geven?

Als ik het zo lees lijkt me dit echt een typische "Excel applicatie". Een (of meerdere) tabblad(en) met alle invoervelden, en dan een ander tabblad(en) met het rekenwerk (+ evt macro's). Als je PHP alleen maar als veredelde rekenmachine wilt gebruiken zie ik niet zoveel voordelen.

En als je het in Excel doet snapt elke kantoorpipo het. Ook de huis-econoom.

De huidige aanpak zal niet ideaal zijn (en misschien ook nog wel geoptimaliseerd kunnen worden), maar als je dit in PHP met een HTML+javascript+ajax frontend gaat doen, dan snapt niemand anders het (behalve jij - en als ik het zo lees ligt zelfs dat nog niet 100% vast).

Wel goed voor je baangarantie / slecht voor het bedrijf als jij een keer onder lijn 5 komt.



Toevoeging op 15/10/2017 09:48:36:

Andersom: Ben je niet gewoon op zoek naar extract? Kun je al je parameters direct als variabele aanroepen, ipv steeds $a['...'] te moeten schrijven.


Hee, dat wist ik niet... In Excel cellen een naam geven. Daar ga ik zeker even naar kijken, omdat mijn bron-sheet niet geheel foutloos is gebleken.

En ja: dit is imho een typische Excel applicatie. Echter mag deze straks door de branche gebruikt gaan worden via de website van mijn werkgever (tegen betaling), en dus mag de sheet niet in verkeerde handen vallen.

Dus we gaan idd voor Ajax/JS aan de frontend (is al klaar, is zelfs netjes multilinguaal tot de button teksten aan toe). Overigens delen front en back een tabel met alle veldnamen(ja, die stomme array $a), dus één veld toevoegen en de frontend is gelijk bijgewerkt. (7 tabbladen, 36 collapsible divs daarbinnen en zo'n 250 vragen daar weer in...)

En nee: extract was ik niet naar op zoek. Ik vind het fijn als alles in een array zit. Hoewel deze niet multidimensionaal is, is er wel code samen te nemen:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
$producten = array ('producta', 'productb', 'productc');
foreach ($producten as $currentproduct){
   echo $a[$currentproduct . 'Consumentenprijs');
}


Hoewel dit soort geintjes maar sporadisch te gebruiken zijn, houden ze met name de uitvoer-view compacter.

Thomas van den Heuvel op 15/10/2017 14:49:17:
@Toms Diner begrijp ik het goed dat je direct van Excel naar PHP-code wilt? Of heb je deze Excel-sheets al ge-reverse engineered naar een soort van specificatie? Zoniet, is dat wellicht een idee, zodat je daar van uit kunt na gaan denken over een implementatie in PHP. En als dat jou niet direct lukt heb je meteen een soort van documentatie die verwoordt wat er zou moeten gebeuren zodat je niet helemaal vanaf 0 hoeft te beginnen / niet alles opnieuw hoeft uit te leggen.

Als een 1:1 vertaling uit de hand loopt kan een tussenstap misschien wat meer inzicht verschaffen.


Ja! Hij is ge-reverse engineered, en daarna geoptimaliseerd. Wat een k klus trouwens, dit heeft me bijna vier dagen gekost. Het is zeer makkelijk om in excel de berekeningen voorwaarts te volgen, maar terug.. Zoeken op celgebruik in formules: daar hebben we zelf een tool voor geschreven. Die kleurde ook alle broncellen paars, zodat we ontdekten dat de makers sommige koppelingen verkeerd hadden gekopieerd.

(Overigens weet ik als ICT-er niet zo heel veel van kostprijs berekeningen, maar dat is de laatste weken aardig veranderd)

Frank Nietbelangrijk op 15/10/2017 17:29:02:
Mja ik herken het wel enigzins. Uit zo een Excel bestand proberen al die formules over te nemen in je applicatie is een hels karwei. En inderdaad moeilijk om daar structuur aan te geven.

Een idee waar je voor jezelf maar moet bedenken of je er iets mee kan.

Héé.. Ik zie hier wel mogelijkheden, vooral omdat ik al een VBA-runner heb voor het exporteren van alle formules.. Die genereert iets wat hier op lijkt:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
MarginResults!C3 = GeneralPrices!A6 + SUM(GeneralPrices!D1:GeneralPrices!D6)


Als ik 'em nu nog leer om de SUM's voluit (dus met het noemen van alle cellen) op te slaan, dan ben ik al een heel eind. En dan kan de Excel-sheet als de "bewijslast" dienen: als PHP en Excel continue dezelfde antwoorden geven, dan zijn ze één op één, en dan kan ik alle vragen over de berekeningen doorsturen naar de maker van de sheet.

Helaas heb ik denk ik al een minpuntje: excel is heer en meester in het "door elkaar rekenen". Je hoeft er bij de bouw geen rekening mee te houden dat sommige waarden later pas bekend zullen zijn: excel rekent rond tot alle velden gevuld zijn. In PHP zul je dat eerst moeten detecteren...

En tot slot: een (math) calculation parser: die naam kende ik ook niet. #bookmark#! We gaan morgen de tijd van de baas maar weer eens nutteloos besteden om hier eens een uurtje mee te spelen... Mijn zoektermen leverde telkens niets op, maar dit is in ieder geval al zeer bruikbaar voor het compacter (en leesbaarder!) schrijven van complete formules. Mag ik u bedanken?
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.