1

我对贷方票据进行了一些复杂的计算,第一页是总金额的摘要。我不想做的是遍历所有规定以计算摘要,然后再次遍历它们以呈现详细视图。那么是否可以在添加详细视图后定义可以替换的自定义占位符?或者您是否知道另一种无需运行两次计算即可获得所需结果的方法?

编辑:

这就是我渲染详细视图的方式:

        foreach($this->_creditNote->provisioningClient->customers as $customer)
        {
            $provisions = $customer->getProvisionsByBillingPeriodSum($this->_creditNote->billingPeriod);
            if((count($provisions) >= 3 && $this->y > 230) || $this->y > 250)
            {
                $this->AddPage();
                $this->SetFillColor(240);
                $this->SetDrawColor(0);
                $this->SetFont('Helvetica', 'B', 10);
                $this->Cell(140, 6, 'Die Provisionen im Einzelnen', 'TB', 0, 'L', 1);
                $this->Cell(30, 6, "Beträge", 'TB', 1, 'R', 1);
                $this->SetXY(25, $this->y-11.5);
                $this->SetTextColor(170,170,170);
                $this->SetFont('Helvetica', '', 7);
                $this->Cell(175, 6, 'Seite ' . $this->getAliasNumPage() . ' von ' . $this->getAliasNbPages(), '', 2, 'R');
                $this->SetY($this->y+6);
                $this->SetFont('Helvetica', '', 9);
                $this->SetTextColor(0,0,0);
            }
            if(count($provisions) > 0)
            {
                $customerData = array();
                $this->SetXY(20, $this->y+1);
                $this->SetFont('Helvetica', 'B', 10);
                $this->Cell(140, 0, $customer->contact->name . " (" . $customer->customerNumber . ")");
                //add customer
                $amount = 0;
                $rows = array();
                foreach($provisions as $provision)
                {
                    $text = $provision->description;
                    $description = "";
                    if($provision->period != "onetime")
                    {
                        if($provision->isPartial($this->_creditNote->billingPeriod))
                            $text .= ", anteilig";
                        $description = $provision->periodName . ", " . $provision->getRuntime($this->_creditNote->billingPeriod);
                    }
                    if($description == "")
                        $description = null;
                    $temp = array($text, $provision->isPartial($this->_creditNote->billingPeriod) ? round($provision->getPartialAmount($this->_creditNote->billingPeriod)/100, 2) : $provision->amount / 100, $description);
                    $amount += $temp[1];
                    $rows[] = $temp;
                }
                $this->Cell(30, 0, number_format($amount, 2, ",", ".") . " €", 0, 1, 'R');
                foreach($rows as $row)
                {
                    $this->SetXY(23, $this->y+1);
                    $this->SetFont('Helvetica', '', 8);
                    $this->Cell(137, 0, $row[0]);
                    $this->Cell(30, 0, number_format($row[1], 2, ",", ".") . " €", 0, 1, 'R');
                    if($row[2])
                    {
                        $this->SetXY(26, $this->y + 1);
                        $this->SetFont('Helvetica', 'I', 8);
                        $this->MultiCell(140, 0, $row[2], 0, 'L');
                    }
                }
            }
        }

提前致谢, 托拜厄斯

4

2 回答 2

2

据我了解,您当前的代码如下所示:

// this will contain the computation for every orders
$orders_infos = array();

// you need $orders_infos to be already filled here, but it is done after
$total = 0;
foreach ($orders_infos as $info) {
  $total += $info['total'];
}
$html = "html for the overview page: ".$total; // $total is wrong !
$pdf->writeHTML($html);

// compute infos for every order and display
foreach ($orders as $k => $order) {
  $orders_infos[$k] = compute_order_infos();
  $html = "html for this order page ".$orders_infos[$k]['total'];
  $pdf->writeHTML($html);
}

您的问题是概览页面中的总数不正确,因为您之后运行了计算。更改它的简单方法是运行所有计算,然后才生成结果 PDF,但您说出于某种原因您不希望这样做。

实现您想要的下一个最佳方法是稍微作弊并跟踪要作为闭包运行的命令列表,然后在最后运行它们,这样您可以保留大部分当前代码组织,但仍会执行所有显示然后;

$commands = array();

// this will contain the computation for every orders
$orders_infos = array();

// you need $orders_infos to be already filled here, but it is done after
$total = 0;
$commands[] = function($pdf, $orders_infos) {
  foreach ($orders_infos as $info) {
    $total += $info['total'];
  }
  $html = "html for the overview page: ".$total;
  $pdf->writeHTML($html);
};

// compute infos for every order and display
foreach ($orders as $k => $order) {
  $orders_infos[$k] = compute_order_infos();
  $commands[] = function($pdf, $orders_infos) use ($k) {
    $html = "html for this order page ".$orders_infos[$k]['total'];
    $pdf->writeHTML($html);
  };
}

// now run all the commands
foreach ($commands as $command) {
  $command($pdf, $orders_infos);
}

一旦完成每个计算,您的所有 PDF 编写命令,包括概述,都将在最后执行。

一个类似但更简单的示例,因此您可以更好地了解其工作原理:

$arr = array();
for ($i = 0; $i < 5; $i++) {
  $arr[$i] = $i;
}
$funcs = array();
foreach ($arr as $k => $v) {
  $funcs[] = function($arr) use($k) {
    echo $arr[$k]."\n";
  };
}

foreach ($funcs as $func) {
  echo "func: ";
  $func($arr);
}

显示:

$ php test.php
func: 0
func: 1
func: 2
func: 3
func: 4
于 2013-06-18T10:00:39.227 回答
1

前段时间我不得不做一个类似的任务,因此知道多次迭代是不好的。

我创建了一个类,它将首先进行所有计算。让我们称之为“回报”类。这将遍历自上个月以来收到的所有订单。然后它将创建信息

  • 每个单笔订单(免税/等...)
  • 整体视图(项目数量/总税额/等)

所以它可能看起来像这样

$payoffInfo=new Payoff($arrayWithOrderInfos);

// do creation of tcpdf object include header/footer/ ...
$pdf = new TCPDF();
$pdf->setPDFVersion('1.4');

$pdf->setPrintHeader(FALSE);
$pdf->setPrintFooter(TRUE);

// create first page and set 'overall' like this ...

$pdf->SetFont('Helvetica', '', 12);
$pdf->Cell(0, 0, "Overall amount ".$payoffInfo->getItemCount() , 0, 1, 'L');
$pdf->Ln();

$pdf->SetFont('Helvetica', '', 12);
$pdf->Cell(0, 0,"Overall amount ".$payoffInfo->getOverallAmount() , 0, 1, 'L');
$pdf->Ln();

// include more Overview Informations ...
// Iterate over all single orders ...

foreach($payoffInfo->getOrders() as $item){
    $html = "<p><ul>";
    $html .= "<li>Item ID: ".$item['order_id']."</li>";
    $html .= "<li>Item Price ".$item['price']."</li>";
    $html .= "<li>Item Clear Amount ".$item['price_without_tax']."</li>";
    $html .= "</ul></p>";
    $pdf->writeHTML($html, TRUE, FALSE, TRUE, FALSE, 'L');
}
// Mark Items as billed or sth. else so we don't include them again next month
$payoffInfo->setItemsToStatus("billed"); 

$pdf->Output($yourDesiredLocation, 'F');

为了减少时间并防止在服务器负载高时生成 pdf,我将其移至“任务”(或其他任何内容)。然后在半夜由 cron 作业每月调用一次此任务(取决于您需要的时间段)。

该解决方案适用于每月约 400k 的订单,并且可能做得更多。

如果您想要可以完全按照您想要的样式设置的时尚 pdf,我今天会使用某种 LaTeX“界面”。因为对包括页眉和页脚在内的整个内容进行样式设置要容易得多。

希望这可以帮助您反思您的任务。

于 2013-06-18T10:42:34.873 回答