/** @depends testSaveLine */
 function testSaveMultiLines()
 {
     $date = stdtimefstr("2013-01-01 00:00:00");
     $attrSetInst = new AttributeSetInstance($this->attrSet->id, "Value");
     $attrsId = TicketsService::createAttrSetInst($attrSetInst);
     $line1 = new TicketLine(1, $this->prd, $attrSetInst->id, 1, 12, $this->tax);
     $line2 = new TicketLine(2, $this->prd2, null, 2, 10, $this->tax2);
     $line3 = new TicketLine(3, $this->prd, null, 1.5, 10, $this->tax);
     $payment1 = new Payment("cash", 12, $this->currency->id, 14);
     $payment2 = new Payment("cheque", 25, $this->currency->id, 20);
     $ticket = new Ticket(Ticket::TYPE_SELL, $this->user->id, $date, array($line1, $line2, $line3), array($payment1, $payment2), $this->cash->id, null, null);
     $id = TicketsService::save($ticket, $this->location->id);
     $pdo = PDOBuilder::getPDO();
     $db = DB::get();
     // Check sale lines
     $stmtLines = $pdo->prepare("SELECT * FROM TICKETLINES");
     $this->assertNotEquals($stmtLines->execute(), false, "Ticket query failed");
     $toCheck = array($line1, $line2, $line3);
     $count = 0;
     while ($row = $stmtLines->fetch()) {
         $ref = null;
         $count++;
         if ($row['LINE'] == 1) {
             $ref = $line1;
         } else {
             if ($row['LINE'] == 2) {
                 $ref = $line2;
             } else {
                 if ($row['LINE'] == 3) {
                     $ref = $line3;
                 }
             }
         }
         $this->assertNotNull($ref, "Unknown line");
         $this->checkSaleEquality($id, $ref, $row);
         for ($i = 0; $i < count($toCheck); $i++) {
             $l = $toCheck[$i];
             if ($l->dispOrder == $ref->dispOrder) {
                 array_splice($toCheck, $i, 1);
                 break;
             }
         }
     }
     $this->assertEquals(3, $count, "Sale line count mismatch");
     $this->assertEquals(0, count($toCheck), "Duplicated sale lines");
     // Check tax lines
     $stmtTax = $pdo->prepare("SELECT * FROM TAXLINES");
     $this->assertNotEquals($stmtTax->execute(), false, "Tax lines query failed");
     $toCheck = array($this->tax->id, $this->tax2->id);
     for ($i = 0; $i < 2; $i++) {
         $row = $stmtTax->fetch();
         $this->assertNotEquals(false, $row, "Not enough tax line found");
         $ref = null;
         if ($row['TAXID'] == $this->tax->id) {
             $ref = $this->tax->id;
             $this->checkTaxEquality($id, $ref, 27, 2.7, $row);
         } else {
             if ($row['TAXID'] == $this->tax2->id) {
                 $ref = $this->tax2->id;
                 $this->checkTaxEquality($id, $ref, 20, 4, $row);
             }
         }
         $this->assertNotNull($ref, "Unknown tax line");
         foreach ($toCheck as $j => $taxId) {
             if ($ref == $taxId) {
                 array_splice($toCheck, $j, 1);
                 break;
             }
         }
     }
     $this->assertEquals(0, count($toCheck), "Duplicated tax lines");
     $row = $stmtTax->fetch();
     $this->assertFalse($row, "Too much tax lines found");
     // Check payment lines
     $toCheck = array($payment1, $payment2);
     $stmtPmt = $pdo->prepare("SELECT * FROM PAYMENTS");
     $this->assertNotEquals($stmtPmt->execute(), false, "Payment lines query failed");
     $count = 0;
     while ($row = $stmtPmt->fetch()) {
         $ref = null;
         $count++;
         if ($row['PAYMENT'] == "cash") {
             $ref = $payment1;
         } else {
             if ($row['PAYMENT'] == "cheque") {
                 $ref = $payment2;
             }
         }
         $this->assertNotNull($ref, "Unknown line");
         $this->checkPaymentEquality($id, $ref, $row);
         foreach ($toCheck as $i => $pmt) {
             if ($pmt->type == $ref->type) {
                 array_splice($toCheck, $i, 1);
                 break;
             }
         }
     }
     $this->assertEquals(2, $count, "Payment line count mismatch");
     $this->assertEquals(0, count($toCheck), "Duplicated payment lines");
     // Check stocks
     $level = StocksService::getLevel($this->prd->id, $this->location->id, null);
     $this->assertEquals(-1.5, $level->qty);
     $level = StocksService::getLevel($this->prd2->id, $this->location->id, null);
     $this->assertEquals(-2, $level->qty);
     $this->markTestIncomplete("Check stock level with attribute");
 }
 /** @depends testCreateMoveBuy
  * @depends testReadLevel
  */
 public function testReadQty()
 {
     $level = new StockLevel($this->products[0]->id, $this->locations[0]->id, null, 1.2, 15.6, 3.5);
     // Quantity is set matching to move
     $level->id = StocksService::createLevel($level);
     $move = new StockMove(stdtimefstr("2014-01-01 00:00:00"), StockMove::REASON_IN_BUY, $level->productId, $level->locationId, $level->attrSetInstId, $level->qty, 10);
     $move->id = StocksService::addMove($move);
     $read = StocksService::getLevel($move->productId, $move->locationId, $move->attrSetInstId);
     $this->checkEquality($read, $level);
 }
 /** Create an inventory. If date, missingQty or unitValue is null they are
  * computed from current stock and current date. */
 public function create($inventory)
 {
     $pdo = PDOBuilder::getPDO();
     $db = DB::get();
     $newTransaction = !$pdo->inTransaction();
     if ($newTransaction) {
         $pdo->beginTransaction();
     }
     if ($inventory->date === null) {
         // Set date to now
         $inventory->date = time();
     }
     // Insert inventory
     $invStmt = $pdo->prepare("INSERT INTO STOCK_INVENTORY (DATE, " . "LOCATION_ID) VALUES (:date, :locId)");
     $invStmt->bindParam(":date", $db->dateVal($inventory->date));
     $invStmt->bindParam(":locId", $inventory->locationId);
     if ($invStmt->execute() !== false) {
         $id = $pdo->lastInsertId(static::$dbTable . "_" . static::$dbIdField . "_seq");
     } else {
         if ($newTransaction) {
             $pdo->rollback();
         }
         return false;
     }
     // Parse and insert items
     $stmt = $pdo->prepare("INSERT INTO STOCK_INVENTORYITEM (INVENTORY_ID, " . "PRODUCT_ID, ATTRSETINST_ID, QTY, LOSTQTY, DEFECTQTY, " . "MISSINGQTY, UNITVALUE) VALUES " . "(:id, :prdId, :attrId, :qty, :lostQty, :defectQty, " . ":missingQty, :unitValue)");
     $stmt->bindParam(":id", $id);
     foreach ($inventory->items as $item) {
         if ($item->missingQty === null) {
             // Check for missing count on current stock
             $lvl = StocksService::getLevel($item->productId, $inventory->locationId, $item->attrSetInstId);
             if ($lvl != null) {
                 $qty = $lvl->qty;
                 $invQty = $item->qty + $item->lostQty + $item->defectQty;
                 $item->missingQty = $qty - $invQty;
             } else {
                 $item->missingQty = 0;
             }
         }
         if ($item->unitValue === null) {
             // Compute average value
             $sql = "SELECT REASON, UNITS, PRICE FROM STOCKDIARY " . "WHERE LOCATION = :loc AND PRODUCT = :prd";
             if ($item->attrSetInstId !== null) {
                 $sql .= " AND ATTRIBUTESETINSTANCE_ID = :attr";
             } else {
                 $sql .= " AND ATTRIBUTESETINSTANCE_ID IS NULL";
             }
             $sql .= " ORDER BY DATENEW DESC";
             $stmtVal = $pdo->prepare($sql);
             $stmtVal->bindParam(":loc", $item->locationId);
             $stmtVal->bindParam(":prd", $item->productId);
             if ($item->attrSetInstId !== null) {
                 $stmtVal->bindParam(":attr", $item->attrSetInstId);
             }
             $stmtVal->execute();
             $units = 0;
             $expectedUnits = $item->getTotalQty();
             $price = 0.0;
             while ($row = $stmtVal->fetch() && $units != $expectedUnits) {
                 $units += $row['UNITS'];
                 if ($row['UNITS'] > 0) {
                     $price += $row['PRICE'];
                 } else {
                     $price -= $row['PRICE'];
                 }
             }
             if ($units != 0) {
                 $item->unitValue = $price / $units;
             } else {
                 $item->unitValue = 0;
             }
         }
         // Insert
         $stmt->bindParam(":prdId", $item->productId);
         $stmt->bindParam(":attrId", $item->attrSetInstId);
         $stmt->bindParam(":qty", $item->qty);
         $stmt->bindParam(":lostQty", $item->lostQty);
         $stmt->bindParam(":defectQty", $item->defectQty);
         $stmt->bindParam(":missingQty", $item->missingQty);
         $stmt->bindParam(":unitValue", $item->unitValue);
         if ($stmt->execute() === false) {
             var_dump($stmt->errorInfo());
             if ($newTransaction) {
                 $pdo->rollback();
             }
             return false;
         }
     }
     if ($newTransaction) {
         $pdo->commit();
     }
     return $id;
 }