Home > Blockchain >  How to validate that the total can have a margin difference of - 1 cent
How to validate that the total can have a margin difference of - 1 cent

Time:07-29

I am in the search for a solution to allow the loading of an XML file where the value named as Total allows a difference of 1 cent above or below the actual value, for this solution I am getting the value of Total from the XML file as follows.

$xml = new SimpleXMlElement( $_FILES['XmlToUpload']['tmp_name'], 0, true );
$total = (float)$xml['Total'];

To explain in detail what I want to achieve I will put the following example, when reading the Total node of the XML file this gets as a value the following Total= "9840.00", what I want to allow when loading the XML file is that it allows that total to have a difference of more or less 1 cent, that is, that even if the Total of the XML file has a value of Total="9839.99" or Total="9840.01" it allows the file to be loaded.

The XML file is loaded as follows:

$fileXML = $_FILES['XmlToUpload']['name'];
$pathXML = "//LOCATION/XML/";
    
$filepathXML = $pathXML.$fileXML;



if(move_uploaded_file( $_FILES['XmlToUpload']['tmp_name'], $pathXML . $fileXML)){

echo 'Success Upload File'; 

}

I hope someone can give me some guidance on how to do this validation.

Update 1:

I add a short and representative sample of my XML file in which the Total node that was desired to validate is located

<cfdi:Voucher xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
Certificated="m4gfzi9yNXuC0A=" 
Condition="002" 
Date="2021-06-29T16:02:16" 
Number="4938" 
Payment="23" 
NoCertificated="404627114" 
Total="9840.00" 
Version="3.3">
</cfdi:Voucher>

Update 2:

I tried to make a modification in my code based on one of the answers they give me, but I can't exist, it may be some additional error I have, what I tried was to add two new variables, one adding to the total an amount of "0.01" and the other variable subtract the amount of "0.01".

The variables are declared as follows:

$totalMgS = $total   "0.01";
$totalMgI = $total - "0.01";

It is important to make it clear that $total I mentioned before at the beginning of the question, which I use to read the XML file.

Based on one of the responses I created the following validation in the loading section of my XML file:

if($total <= $totalMgS && $total >= $totalMgI){
if(move_uploaded_file( $_FILES['XmlToUpload']['tmp_name'], $pathXML . $fileXML)){

echo 'Success Upload File'; 

}
}else{
echo "It doesn't fit!";

When I test an XML file where $total has a difference of 0.01, the file is not loaded and throws me the message of It doesn't fit!.

Any changes I need to make to my validation?

CodePudding user response:

First, the sample xml in your question is not well formed since it doesn't include a namespace declaration for cfdi.

Assuming that's corrected as in the example below, you can use xpath to compare the Total value with your limits and than do whatever you need to do:

#note the change to the first line
$xml = '<cfdi:Voucher xmlns:cfdi="http://www.sat.gob.mx/cfd/3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              Certificated="m4gfzi9yNXuC0A=" 
              Condition="002" 
              Date="2021-06-29T16:02:16" 
              Number="4938" 
              Payment="23" 
              NoCertificated="404627114" 
              Total="9840.00" 
              Version="3.3">
</cfdi:Voucher>
';
$doc = new SimpleXMLElement($xml);
#one way to handle the namespaces:
$target = $doc->xpath('//*[local-name()="Voucher"]/@Total')[0];

if ($target <= 9840.01 && $target >= 9839.99) {
  echo "It fits!";
} else {
  echo "It doesn't fit!";
};

CodePudding user response:

Float is not suitable for commercial calculations where accuracy is important. Calculations with float values often bring inaccuracies. Example:

$diff = "9840.01" - "9840.00";
var_dump($diff);  //float(0.010000000000218)
var_dump($diff > 0.01);  //bool(true)

The difference from the default is exactly 1 cent. A comparison by float would show that the difference is more than 1 cent. I don't want to go into detail about the causes, there are thousands of posts on the net (Why not use Double or Float to represent currency?)

One possible solution is to use BCMath (Arbitrary Precision Mathematics).

function isDiffGt1Cent(string $actual, string $ref): bool
{
  $diff = bcsub($actual,$ref,3);
  return bccomp($diff,"0.01",3) === 1 OR bccomp($diff,"-0.01",3) === -1;
}

$d0 = isDiffGt1Cent("9840.00","9840.00");  // bool(false)
$d1 = isDiffGt1Cent("9840.01","9840.00");  // bool(false)
$d2 = isDiffGt1Cent("9839.99","9840.00");  // bool(false)
$d3 = isDiffGt1Cent("9840.02","9840.00");  // bool(true)
$d4 = isDiffGt1Cent("9839.98","9840.00");  // bool(true)
  • Related