в настоящее время я могу сделать обновление, но не автоматически, я чувствую, что это некрасиво, я гуглю и думаю, что есть другой способ автоматически обновить поле «ссылка» и подсчитать общую цену для каждого элемента (цена * количество) и сохранить в БД, пример
у клиента может быть много счетов, в счете может быть много товаров
структура таблицы:
клиент — идентификатор (AI), имя пользователя, [……]
invoice — id (AI), client_id (refenrece (client.id)), [……]
invoice_item — id (AI), invoice_id (ссылка (invoice.id)), продукт, […..]
То, что я хочу, это каждый раз, когда я создаю новый счет-фактуру, который я могу добавить много элементов на странице, а затем, когда я отправляю, действие вставить новый счет-фактуру, вставить весь элемент счета-фактуры и обновить invoice_item
,invoice_id
поле
в настоящее время я сделал это, но очень глупо, и я думаю, что есть лучший способ
$client = $this->findClientById($id);
if (null == $client) {
return $this->handleNotFound();
}
$invoice = new Invoice();
$invoice->setClient($client);
$invoice->setStat(0);
$form = $this->createCreateForm($invoice, $id);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->get('doctrine')->getManager();
$data = $form->getData();
//Here i loop all the invoice item
//set the related id
//Count the total
foreach ($data->getItem() as $key => $var) {
$var->setInvoice($invoice);
$var->countTotalAmount();
if ($var->getId() != null) {
$ids[] = $var->getId();
}
}
$em->persist($form->getData());
$em->flush();
$this->addFlash('success', 'Invoice is created.');
return $this->redirectToRoute('client_invoice_list', array('id' => $id));
и я Google вокруг, я нашел, может сделать как следующее, поэтому я попробую
Счет-фактура
/**
* @ORM\OneToMany(targetEntity="InvoiceItem", mappedBy="invoice", cascade={"all"}, orphanRemoval=true)
*/
protected $item;
cascade
это то, что я нашел, выполнив поиск в Google, и это также внутри сущности счета
/**
* Add item
*
* @param \Webulous\EcocrmBundle\Entity\InvoiceItem $item
* @return Invoice
*/
public function addItem(\Webulous\EcocrmBundle\Entity\InvoiceItem $item)
{
$item->setInvoice($this);
$this->item[] = $item;
return $this;
}
$item->setInvoice($this);
это то, что я тоже получил от Google,
я удаляю цикл из действия контроллера и пытаюсь, но не повезло (может быть, я что-то пропустил), есть ошибка
insert into invoice_item([.....], invoice_id) values([......], null), invoice_id cannot be null
контроллер:
class InvoiceController extends Controller {
private function findClientById($id) {
return $this->get('doctrine')->getRepository('WebulousEcocrmBundle:Client')->find($id);
}
private function findInvoiceById($id) {
return $this->get('doctrine')->getRepository('WebulousEcocrmBundle:Invoice')->find($id);
}
private function handleNotFound() {
$this->addFlash('danger', 'Client not found.');
return $this->redirectToRoute('client_list');
}
private function handleInvoiceNotFound($uid) {
$this->addFlash('danger', 'Invoice not found.');
return $this->redirectToRoute('client_invoice_list', array('id' => $uid));
}
private function handleInvoiceCompleted($id) {
$this->addFlash('danger', 'for invoice status is Paid cannot be edit.');
return $this->redirectToRoute('client_invoice_list', array('id' => $id));
}
public function listAction($id, Request $request) {
$client = $this->findClientById($id);
if (null === $client) {
return $this->handleNotFound();
}
$invoice = $this->get('knp_paginator')->paginate(
$client->getInvoice(), $request->query->get('page', 1), 30
);
return $this->render('WebulousEcocrmBundle:Invoice:list.html.twig', array(
'_action' => 'clients',
'invoice' => $invoice,
'client' => $client,
));
}
private function getProduct() {
return $this->getDoctrine()->getRepository('Webulous\EcocrmBundle\Entity\Product')->findBy(array('deleted' => 1));
}
public function createAction($id, Request $request) {
$client = $this->findClientById($id);
if (null == $client) {
return $this->handleNotFound();
}
$invoice = new Invoice();
$invoice->setClient($client);
$invoice->setStat(0);
$form = $this->createCreateForm($invoice, $id);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->get('doctrine')->getManager();
$data = $form->getData();
foreach ($data->getItem() as $key => $var) {
$var->setInvoice($invoice);
$var->countTotalAmount();
if ($var->getId() != null) {
$ids[] = $var->getId();
}
}
$em->persist($form->getData());
$em->flush();
$this->addFlash('success', 'Invoice is created.');
return $this->redirectToRoute('client_invoice_list', array('id' => $id));
} else {
$errors = (string) $form->getErrors(true);
$form->addError(new FormError($errors));
}
return $this->render('WebulousEcocrmBundle:Invoice:create.html.twig', array(
'_action' => 'clients',
'form' => $form->createView(),
'product' => $this->getProduct(),
));
}
public function createFormAction($id, Request $request) {
$client = $this->findClientById($id);
if (null == $client) {
return $this->handleNotFound();
}
$invoice = new Invoice();
$form = $this->createCreateForm($invoice, $id);
return $this->render('WebulousEcocrmBundle:Invoice:create.html.twig', array(
'_action' => 'clients',
'form' => $form->createView(),
'product' => $this->getProduct(),
));
}
private function createCreateForm(Invoice $invoice, $id) {
$form = $this->createForm(new InvoiceType, $invoice, array(
'method' => 'POST',
'action' => $this->generateUrl('client_invoice_create_form', array('id' => $id)),
));
$form->add('stat', 'hidden', array('data' => 0));
$form->add('submit', 'submit');
return $form;
}
public function updateAction($uid, $id, Request $request) {
$client = $this->findClientById($uid);
if (null === $client) {
return $this->handleNotFound();
}
$invoice = $this->findInvoiceById($id);
if (null === $invoice || $invoice->getClient()->getId() != $uid) {
return $this->handleInvoiceNotFound($uid);
}
$em = $this->get('doctrine')->getManager();
$submittedData = $request->get('webulous_ecocrmbundle_invoice', null, true);
$form = $this->createUpdateForm($invoice, $uid, $id);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->get('doctrine')->getManager();
$data = $form->getData();
foreach ($data->getItem() as $key => $var) {
$var->setInvoice($invoice);
$var->countTotalAmount();
if ($var->getId() != null) {
$ids[] = $var->getId();
}
}
// Delete all the non exists row
$items = $em->getRepository('WebulousEcocrmBundle:InvoiceItem')->findMissingItemInInvoice($ids);
foreach ($items as $item) {
//Delete the item
$em->remove($item);
$em->flush();
}
$em->persist($form->getData());
$em->flush();
$this->addFlash('success', 'Invoice is updated.');
return $this->redirectToRoute('client_invoice_list', array('id' => $uid));
} else {
$errors = (string) $form->getErrors(true);
$form->addError(new FormError($errors));
}
$form = $this->createUpdateForm($invoice, $uid, $id);
return $this->render('WebulousEcocrmBundle:Invoice:update.html.twig', array(
'_action' => 'clients',
'invoice' => $invoice,
'form' => $form->createView(),
'client' => $client,
'update' => true,
));
}
public function updateFormAction($uid, $id, Request $request) {
$client = $this->findClientById($uid);
if (null === $client) {
return $this->handleNotFound();
}
$invoice = $this->findInvoiceById($id);
if (null === $invoice || $invoice->getClient()->getId() != $uid) {
return $this->handleInvoiceNotFound($uid);
}
if (Invoice::STATUS_PAID == $invoice->getStat()) {
return $this->handleInvoiceCompleted($uid);
}
$form = $this->createUpdateForm($invoice, $uid, $id);
return $this->render('WebulousEcocrmBundle:Invoice:update.html.twig', array(
'_action' => 'clients',
'invoice' => $invoice,
'form' => $form->createView(),
'client' => $client,
'update' => true,
'product' => $this->getProduct(),
));
}
private function createUpdateForm(Invoice $invoice, $uid, $id) {
$form = $this->createForm(new InvoiceType, $invoice, array(
'method' => 'POST',
'action' => $this->generateUrl('client_invoice_update_form', array('uid' => $uid, 'id' => $id)),
));
$form->add('stat', 'choice', array(
'label' => 'Payment Status',
'choices' => Invoice::getPaymentChoices()
));
$form->add('submit', 'submit');
return $form;
}
}
субъект счета-фактуры:
<?php
namespace Webulous\EcocrmBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Invoice
*
* @ORM\Table("invoice")
* @ORM\Entity(repositoryClass="Webulous\EcocrmBundle\Entity\InvoiceRepository")
* @ORM\HasLifecycleCallbacks()
*/
class Invoice
{
const STATUS_UNPAID = 0;
const STATUS_PAID = 1;
const STATUS_CANCELLED = 2;
const TAX_CHARGE_PERCENTAGE = 1;
const TAX_CHARGE_FIXED = 2;
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity="Client", inversedBy="invoice")
* @ORM\JoinColumn(name="client_id", referencedColumnName="id", nullable=false)
*/
protected $client;
/**
* @ORM\OneToMany(targetEntity="InvoiceItem", mappedBy="invoice", cascade={"all"}, orphanRemoval=true)
*/
protected $item;
/**
* @var integer
*
* @ORM\Column(name="stat", type="smallint")
*/
private $stat;
/**
* @var integer
*
* @ORM\Column(name="created", type="integer")
*/
private $created;
/**
* @var integer
*
* @ORM\Column(name="updated", type="integer")
*/
private $updated;
[......]
/**
* @var integer
*
*/
private $total;
/**
* Constructor
*/
public function __construct()
{
$this->item = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
public function getInvoiceId() {
return 'MPN#' . str_pad($this->id, 6, '0', STR_PAD_LEFT);
}
/**
* Set stat
*
* @param integer $stat
* @return Invoice
*/
public function setStat($stat)
{
$this->stat = $stat;
return $this;
}
/**
* Get stat
*
* @return integer
*/
public function getStat()
{
return $this->stat;
}
/**
* Set created
*
* @param integer $created
* @return Invoice
*/
public function setCreated($created)
{
$this->created = $created;
return $this;
}
/**
* Get created
*
* @return integer
*/
public function getCreated()
{
return $this->created;
}
/**
* Set updated
*
* @param integer $updated
* @return Invoice
*/
public function setUpdated($updated)
{
$this->updated = $updated;
return $this;
}
/**
* Get updated
*
* @return integer
*/
public function getUpdated()
{
return $this->updated;
}
[......]
public function getStatExplain() {
return $this->transformStat($this->getStat());
}
private function transformStat($value) {
switch ($value) {
case self::STATUS_UNPAID:
return 'Unpaid';
case self::STATUS_PAID:
return 'Paid';
case self::STATUS_CANCELLED:
return 'Cancelled';
default:
return 'Unpaid';
}
}
private function reverseTransformStat($value) {
switch ($value) {
case 'Unpaid':
return self::STATUS_UNPAID;
case 'Paid':
return self::STATUS_PAID;
case 'Cancelled':
return self::STATUS_CANCELLED;
default:
return self::STATUS_UNPAID;
}
}
/** @ORM\PrePersist */
public function prePresist() {
$this->created = time();
$this->updated = time();
}
/** @ORM\PreUpdate */
public function preUpdate() {
$this->updated = time();
}
/**
* Set client
*
* @param \Webulous\EcocrmBundle\Entity\Client $client
* @return Invoice
*/
public function setClient(\Webulous\EcocrmBundle\Entity\Client $client = null)
{
$this->client = $client;
return $this;
}
/**
* Get client
*
* @return \Webulous\EcocrmBundle\Entity\Client
*/
public function getClient()
{
return $this->client;
}
/**
* Set total
*
* @param integer $total
* @return Invoice
*/
public function setTotal($total) {
$this->total = $total;
return $this;
}
/**
* Get item count
*
* @return integer
*/
public function getTotalItemCount() {
$total = 0;
foreach($this->getItem() as $item) {
$total += $item->getQuantity();
}
return $total;
}
public static function getPaymentChoices() {
return array(
self::STATUS_UNPAID => 'Unpaid',
self::STATUS_PAID => 'Paid',
self::STATUS_CANCELLED => 'Cancelled'
);
}
/**
* Set item
*
* @param \Webulous\EcocrmBundle\Entity\InvoiceItem $item
* @return Invoice
*/
public function setItem(\Webulous\EcocrmBundle\Entity\InvoiceItem $item = null)
{
if (null === $item) {
return $this;
}
$this->addItem($item);
return $this;
}
/**
* Add item
*
* @param \Webulous\EcocrmBundle\Entity\InvoiceItem $item
* @return Invoice
*/
public function addItem(\Webulous\EcocrmBundle\Entity\InvoiceItem $item)
{
$item->setInvoice($this);
$this->item[] = $item;
return $this;
}
/**
* Remove item
*
* @param \Webulous\EcocrmBundle\Entity\InvoiceItem $item
*/
public function removeItem(\Webulous\EcocrmBundle\Entity\InvoiceItem $item)
{
$this->item->removeElement($item);
}
/**
* Get item
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getItem()
{
return $this->item;
}
/**
* Count all item total
*
* @return float
*/
public function getTotalPrice()
{
$sum = 0;
foreach($this->getItem() as $key => $var) {
$sum += $var->getTotalAmount();
}
return $this->roundNumber($sum);
}
/**
* Count total tax
*
* @return float
*/
public function getTotalTax()
{
if($this->getTax() != NULL && in_array($this->getTaxType(), array(self::TAX_CHARGE_FIXED, self::TAX_CHARGE_PERCENTAGE))) {
$tax = $this->getTaxExplain();
}
switch($this->getTaxType()) {
case self::TAX_CHARGE_FIXED:
return $tax;
break;
case self::TAX_CHARGE_PERCENTAGE:
return ($this->getTotalPrice() / 100) * $tax;
break;
default:
return NULL;
break;
}
}
/**
* Count all item total with tax
*
* @return float
*/
public function getTotalPriceWithTax()
{
return $this->roundNumber($this->getTotalPrice() + $this->getTotalTax());
}
/**
* Round the number
*
* @return float
*/
public function roundNumber($float)
{
return number_format((float)$float, 2, '.', '');
}
}
объект InvoiceItem:
<?php
namespace Webulous\EcocrmBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Webulous\EcocrmBundle\Entity\Invoice;
/**
* InvoiceItem
*
* @ORM\Entity(repositoryClass="Webulous\EcocrmBundle\Entity\InvoiceItemRepository")
* @ORM\HasLifecycleCallbacks()
* @ORM\Table(name="invoice_item")
*/
class InvoiceItem
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var integer
*
* @ORM\ManyToOne(targetEntity="Webulous\EcocrmBundle\Entity\Invoice", inversedBy="item")
* @ORM\JoinColumn(name="invoice_id", referencedColumnName="id", nullable=false)
*/
private $invoice;
/**
* @var integer
*
* @ORM\ManyToOne(targetEntity="Webulous\EcocrmBundle\Entity\Product")
* @ORM\JoinColumn(name="product_id", referencedColumnName="id", nullable=false)
*/
private $product;
/**
* @var string
*
* @ORM\Column(name="description", type="text", nullable=true)
*/
private $description;
[......]
/**
* @var float
*
* @ORM\Column(name="price", type="float", scale=2)
*/
private $price;
/**
* @var float
*
* @ORM\Column(name="total_amount", type="float", scale=2)
*/
private $totalAmount;
/**
* @ORM\Column(name="created_at", type="datetime")
* @Gedmo\Timestampable(on="create")
*/
private $createdAt;
/**
* @ORM\Column(name="updated_at", type="datetime")
* @Gedmo\Timestampable(on="update")
*/
private $updatedAt;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set invoice
*
* @param Invoice
* @return InvoiceItem
*/
public function setInvoice($invoice)
{
$this->invoice = $invoice;
return $this;
}
/**
* Get invoice
*
* @return Invoice
*/
public function getInvoice()
{
return $this->invoice;
}
/**
* Set product
*
* @param Product
* @return InvoiceItem
*/
public function setProduct($product)
{
$this->product = $product;
return $this;
}
/**
* Get product
*
* @return Product
*/
public function getProduct()
{
return $this->product;
}
[......]
/**
* Set quantity
*
* @param float $quantity
* @return InvoiceItem
*/
public function setQuantity($quantity)
{
$this->quantity = $quantity;
return $this;
}
/**
* Get quantity
*
* @return float
*/
public function getQuantity()
{
return $this->quantity;
}
/**
* Set price
*
* @param float $price
* @return InvoiceItem
*/
public function setPrice($price)
{
$this->price = $price;
return $this;
}
/**
* Get price
*
* @return float
*/
public function getPrice()
{
return $this->price;
}
/**
* Set totalAmount
*
* @param float $totalAmount
* @return InvoiceItem
*/
public function setTotalAmount($totalAmount)
{
$this->totalAmount = $totalAmount;
return $this;
}
/**
* Get totalAmount
*
* @return float
*/
public function getTotalAmount()
{
return $this->totalAmount;
}
/**
* Set createdAt
*
* @param \DateTime $createdAt
* @return Invoice
*/
public function setCreatedAt($createdAt)
{
$this->createdAt = $createdAt;
return $this;
}
/**
* Get createdAt
*
* @return \DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* Get updatedAt
*
* @return \DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
/**
* Set updatedAt
*
* @param \DateTime $updatedAt
* @return Invoice
*/
public function setUpdatedAt($updatedAt)
{
$this->updatedAt = $updatedAt;
return $this;
}
/** @ORM\PrePersist */
public function prePresist() {
$this->setCreatedAt(new \DateTime);
$this->setUpdatedAt(new \DateTime);
}
/** @ORM\PreUpdate */
public function preUpdate() {
$this->setUpdatedAt(new \DateTime);
}
public function getProductName() {
return $this->getProduct()->getProductName();
}
public function countTotalAmount() {
$price = $this->getPrice();
$quantity = $this->getQuantity();
$total = $this->getInvoice()->roundNumber(($price * $quantity));
$this->setTotalAmount($total);
return $this->getTotalAmount();
}
}
тип формы счета-фактуры:
public function buildForm(FormBuilderInterface $builder, array $options)
{
[......]
->add('item', 'collection', array(
'type' => new InvoiceItemType(),
'allow_add' => true,
'allow_delete' => true,
'options' => array(
)
))
}
Задача ещё не решена.
Других решений пока нет …