diff --git a/composer.json b/composer.json index d57ff137c..e82f6c984 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,7 @@ "prefer-stable": true, "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { diff --git a/src/Marello/Bundle/CatalogBundle/Entity/Category.php b/src/Marello/Bundle/CatalogBundle/Entity/Category.php index 4a0744fe6..9c6be361a 100755 --- a/src/Marello/Bundle/CatalogBundle/Entity/Category.php +++ b/src/Marello/Bundle/CatalogBundle/Entity/Category.php @@ -17,8 +17,8 @@ * @ORM\Table(name="marello_catalog_category", * uniqueConstraints={ * @ORM\UniqueConstraint( - * name="marello_catalog_category_codeidx", - * columns={"code"} + * name="marello_catalog_category_codeorgidx", + * columns={"code", "organization_id"} * ) * } * ) @@ -218,6 +218,7 @@ public function addProduct(Product $product) { if (!$this->hasProduct($product)) { $this->products->add($product); + $product->addCategoryCode($this->getCode()); } return $this; @@ -230,6 +231,7 @@ public function addProduct(Product $product) public function removeProduct(Product $product) { if ($this->hasProduct($product)) { + $product->removeCategory($this); $this->products->removeElement($product); } diff --git a/src/Marello/Bundle/CatalogBundle/Entity/Repository/CategoryRepository.php b/src/Marello/Bundle/CatalogBundle/Entity/Repository/CategoryRepository.php index 584198873..743501e59 100644 --- a/src/Marello/Bundle/CatalogBundle/Entity/Repository/CategoryRepository.php +++ b/src/Marello/Bundle/CatalogBundle/Entity/Repository/CategoryRepository.php @@ -3,6 +3,9 @@ namespace Marello\Bundle\CatalogBundle\Entity\Repository; use Doctrine\ORM\EntityRepository; +use Marello\Bundle\CatalogBundle\Entity\Category; +use Marello\Bundle\ProductBundle\Entity\Product; +use Marello\Bundle\SalesBundle\Entity\SalesChannel; use Oro\Bundle\SecurityBundle\ORM\Walker\AclHelper; class CategoryRepository extends EntityRepository @@ -33,4 +36,17 @@ public function findExcludedCategoriesIds(array $relatedCategoriesIds) return $this->aclHelper->apply($qb)->getArrayResult(); } + + /** + * @param Product $product + * @return Category[] + */ + public function findByProduct(Product $product) + { + $qb = $this->createQueryBuilder('c') + ->where(':product MEMBER OF c.products') + ->setParameters(['product' => $product]); + + return $qb->getQuery()->getResult(); + } } diff --git a/src/Marello/Bundle/CatalogBundle/EventListener/Datagrid/CategoriesDatagridListener.php b/src/Marello/Bundle/CatalogBundle/EventListener/Datagrid/CategoriesDatagridListener.php deleted file mode 100644 index 60b5231d3..000000000 --- a/src/Marello/Bundle/CatalogBundle/EventListener/Datagrid/CategoriesDatagridListener.php +++ /dev/null @@ -1,162 +0,0 @@ -relatedEntityClass = $relatedEntityClass; - $this->categoriesChoicesProvider = $categoriesChoicesProvider; - - $this->expressionBuilder = new Expr(); - } - - /** - * @param BuildBefore $event - */ - public function onBuildBefore(BuildBefore $event) - { - $config = $event->getConfig(); - - $this->addSelect($config); - $this->addJoin($config); - $this->addColumn($config); - $this->addSorter($config); - $this->addFilter($config); - } - - /** - * @param DatagridConfiguration $configuration - * @return string - * @throws \InvalidArgumentException when a root entity not found in the grid - */ - protected function getAlias(DatagridConfiguration $configuration) - { - $rootAlias = $configuration->getOrmQuery()->getRootAlias(); - if (!$rootAlias) { - throw new \InvalidArgumentException( - sprintf( - 'A root entity is missing for grid "%s"', - $configuration->getName() - ) - ); - } - - return $rootAlias; - } - - /** - * @return string - */ - protected function getColumnLabel() - { - return 'marello.catalog.category.entity_plural_label'; - } - - /** - * @return string - */ - protected function getDataName() - { - return self::DATA_NAME; - } - - /** - * @return string - */ - protected function getJoinAlias() - { - return self::JOIN_ALIAS; - } - - /** - * @param DatagridConfiguration $config - */ - protected function addSelect(DatagridConfiguration $config) - { - $config->getOrmQuery()->addSelect( - sprintf('count(%s.code) AS categoriesCount', $this->getJoinAlias()) - ); - } - - /** - * @param DatagridConfiguration $config - */ - protected function addJoin(DatagridConfiguration $config) - { - $config->getOrmQuery()->addLeftJoin( - $this->getAlias($config).'.categories', - $this->getJoinAlias() - ); - } - - /** - * @param DatagridConfiguration $config - */ - protected function addColumn(DatagridConfiguration $config) - { - $config->offsetSetByPath(sprintf('[columns][%s]', $this->getDataName()), [ - 'label' => $this->getColumnLabel(), - 'type' => 'twig', - 'frontend_type' => 'html', - 'template' => 'MarelloCatalogBundle:Datagrid/Property:categories.html.twig', - 'renderable' => false - ]); - } - - /** - * @param DatagridConfiguration $config - */ - protected function addSorter(DatagridConfiguration $config) - { - $config->offsetSetByPath( - sprintf('[sorters][columns][%s]', $this->getDataName()), - ['data_name' => 'categoriesCount'] - ); - } - - /** - * @param DatagridConfiguration $config - */ - protected function addFilter(DatagridConfiguration $config) - { - $config->offsetSetByPath( - sprintf('[filters][columns][%s]', $this->getDataName()), - [ - 'type' => 'choice', - 'data_name' => $this->getJoinAlias() . '.code', - 'enabled' => false, - 'options' => [ - 'field_options' => [ - 'multiple' => true, - 'choices' => $this->categoriesChoicesProvider->getCategories() - ] - ] - ] - ); - } -} diff --git a/src/Marello/Bundle/CatalogBundle/Migrations/Schema/MarelloCatalogBundleInstaller.php b/src/Marello/Bundle/CatalogBundle/Migrations/Schema/MarelloCatalogBundleInstaller.php index f6f33fa38..bf35ef7fe 100755 --- a/src/Marello/Bundle/CatalogBundle/Migrations/Schema/MarelloCatalogBundleInstaller.php +++ b/src/Marello/Bundle/CatalogBundle/Migrations/Schema/MarelloCatalogBundleInstaller.php @@ -20,7 +20,7 @@ class MarelloCatalogBundleInstaller implements Installation, ActivityExtensionAw */ public function getMigrationVersion() { - return 'v1_1_1'; + return 'v1_2'; } /** @@ -61,7 +61,7 @@ protected function createCatalogCategoryTable(Schema $schema) $table->addColumn('updated_at', 'datetime', ['notnull' => false]); $table->addColumn('organization_id', 'integer', ['notnull' => false]); $table->setPrimaryKey(['id']); - $table->addUniqueIndex(['code'], 'marello_catalog_category_codeidx'); + $table->addUniqueIndex(['code', 'organization_id'], 'marello_catalog_category_codeorgidx'); $this->activityExtension->addActivityAssociation($schema, 'oro_note', 'marello_catalog_category'); } diff --git a/src/Marello/Bundle/CatalogBundle/Migrations/Schema/v1_2/MarelloCatalogBundle.php b/src/Marello/Bundle/CatalogBundle/Migrations/Schema/v1_2/MarelloCatalogBundle.php new file mode 100644 index 000000000..5e5ad41a9 --- /dev/null +++ b/src/Marello/Bundle/CatalogBundle/Migrations/Schema/v1_2/MarelloCatalogBundle.php @@ -0,0 +1,31 @@ +changeMarelloCatalogCategoryUniqueIndex($schema); + } + + /** + * @param Schema $schema + */ + protected function changeMarelloCatalogCategoryUniqueIndex(Schema $schema) + { + $table = $schema->getTable('marello_catalog_category'); + $table->dropIndex('marello_catalog_category_codeidx'); + $table->addUniqueIndex(['code', 'organization_id'], 'marello_catalog_category_codeorgidx'); + } +} diff --git a/src/Marello/Bundle/CatalogBundle/Resources/config/services.yml b/src/Marello/Bundle/CatalogBundle/Resources/config/services.yml index a4ccf54b1..910595b99 100644 --- a/src/Marello/Bundle/CatalogBundle/Resources/config/services.yml +++ b/src/Marello/Bundle/CatalogBundle/Resources/config/services.yml @@ -20,14 +20,6 @@ services: - '@request_stack' - '@doctrine.orm.entity_manager' - marello_catalog.event_listener.datagrid.products_grid: - class: 'Marello\Bundle\CatalogBundle\EventListener\Datagrid\CategoriesDatagridListener' - arguments: - - 'Marello\Bundle\ProductBundle\Entity\Product' - - '@marello_catalog.provider.categories_choices' - tags: - - { name: kernel.event_listener, event: oro_datagrid.datagrid.build.before.marello-products-grid, method: onBuildBefore } - marello_catalog.listener.datagrid.category_products_column_listener: class: 'Marello\Bundle\CatalogBundle\EventListener\Datagrid\CategoryProductsColumnListener' arguments: @@ -57,3 +49,9 @@ services: calls: - [setAclHelper, ['@oro_security.acl_helper']] + marello_catalog.twig.category_extension: + class: 'Marello\Bundle\CatalogBundle\Twig\CategoryExtension' + arguments: + - '@doctrine' + tags: + - { name: twig.extension } diff --git a/src/Marello/Bundle/CatalogBundle/Resources/config/validation.yml b/src/Marello/Bundle/CatalogBundle/Resources/config/validation.yml index 03f724875..dc7b04ecf 100644 --- a/src/Marello/Bundle/CatalogBundle/Resources/config/validation.yml +++ b/src/Marello/Bundle/CatalogBundle/Resources/config/validation.yml @@ -1,7 +1,7 @@ Marello\Bundle\CatalogBundle\Entity\Category: constraints: - Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity: - fields: code + fields: [code, organization] message: 'marello.catalog.category.messages.error.code' properties: name: diff --git a/src/Marello/Bundle/CatalogBundle/Resources/views/Datagrid/Property/categories.html.twig b/src/Marello/Bundle/CatalogBundle/Resources/views/Datagrid/Property/categories.html.twig deleted file mode 100644 index 873179a78..000000000 --- a/src/Marello/Bundle/CatalogBundle/Resources/views/Datagrid/Property/categories.html.twig +++ /dev/null @@ -1,3 +0,0 @@ -{% for index, category in record.getValue('categories') %} - {{ category|trans }}
-{% endfor %} \ No newline at end of file diff --git a/src/Marello/Bundle/CatalogBundle/Twig/CategoryExtension.php b/src/Marello/Bundle/CatalogBundle/Twig/CategoryExtension.php new file mode 100644 index 000000000..18ad25617 --- /dev/null +++ b/src/Marello/Bundle/CatalogBundle/Twig/CategoryExtension.php @@ -0,0 +1,68 @@ +doctrine = $doctrine; + } + + /** + * Returns the name of the extension. + * + * @return string The extension name + */ + public function getName() + { + return self::NAME; + } + + /** + * Returns a list of functions to add to the existing list. + * + * @return array An array of functions + */ + public function getFunctions() + { + return [ + new TwigFunction( + 'marello_get_category_name_by_code', + [$this, 'getCategoryNameByCode'] + ) + ]; + } + + /** + * @param string $code + * @return string + */ + public function getCategoryNameByCode($code) + { + $category = $this->doctrine + ->getManagerForClass(Category::class) + ->getRepository(Category::class) + ->findOneBy(['code' => $code]); + if ($category) { + return $category->getName(); + } + + return $code; + } +} diff --git a/src/Marello/Bundle/CustomerBundle/Autocomplete/CompanyCustomerHandler.php b/src/Marello/Bundle/CustomerBundle/Autocomplete/CompanyCustomerHandler.php index 597fd2278..eae8e8371 100644 --- a/src/Marello/Bundle/CustomerBundle/Autocomplete/CompanyCustomerHandler.php +++ b/src/Marello/Bundle/CustomerBundle/Autocomplete/CompanyCustomerHandler.php @@ -3,10 +3,10 @@ namespace Marello\Bundle\CustomerBundle\Autocomplete; use Marello\Bundle\CustomerBundle\Entity\Company; -use Oro\Bundle\FormBundle\Autocomplete\SearchHandler; +use Oro\Bundle\FormBundle\Autocomplete\FullNameSearchHandler; use Doctrine\ORM\QueryBuilder; -class CompanyCustomerHandler extends SearchHandler +class CompanyCustomerHandler extends FullNameSearchHandler { /** * {@inheritdoc} diff --git a/src/Marello/Bundle/CustomerBundle/Entity/Company.php b/src/Marello/Bundle/CustomerBundle/Entity/Company.php index 991b960ff..56a09eb19 100644 --- a/src/Marello/Bundle/CustomerBundle/Entity/Company.php +++ b/src/Marello/Bundle/CustomerBundle/Entity/Company.php @@ -203,6 +203,20 @@ class Company extends ExtendCompany implements OrganizationAwareInterface **/ protected $customers; + /** + * @ORM\Column(name="tax_identification_number", type="string", nullable=true) + * @ConfigField( + * defaultValues={ + * "dataaudit"={ + * "auditable"=true + * } + * } + * ) + * + * @var string + */ + protected $taxIdentificationNumber; + /** * Constructor */ @@ -451,4 +465,24 @@ protected function hasCustomer(Customer $customer) { return $this->customers->contains($customer); } + + /** + * @return string + */ + public function getTaxIdentificationNumber() + { + return $this->taxIdentificationNumber; + } + + /** + * @param string $taxIdentificationNumber + * + * @return $this + */ + public function setTaxIdentificationNumber($taxIdentificationNumber) + { + $this->taxIdentificationNumber = $taxIdentificationNumber; + + return $this; + } } diff --git a/src/Marello/Bundle/CustomerBundle/Entity/Customer.php b/src/Marello/Bundle/CustomerBundle/Entity/Customer.php index f2df2fba5..67b8f24aa 100644 --- a/src/Marello/Bundle/CustomerBundle/Entity/Customer.php +++ b/src/Marello/Bundle/CustomerBundle/Entity/Customer.php @@ -92,20 +92,6 @@ class Customer extends ExtendCustomer implements */ protected $shippingAddress; - /** - * @ORM\Column(name="tax_identification_number", type="string", nullable=true) - * @Oro\ConfigField( - * defaultValues={ - * "dataaudit"={ - * "auditable"=true - * } - * } - * ) - * - * @var string - */ - protected $taxIdentificationNumber; - /** * @ORM\OneToMany( * targetEntity="Marello\Bundle\AddressBundle\Entity\MarelloAddress", @@ -266,26 +252,6 @@ public function getShippingAddress() return $this->shippingAddress; } - /** - * @return string - */ - public function getTaxIdentificationNumber() - { - return $this->taxIdentificationNumber; - } - - /** - * @param string $taxIdentificationNumber - * - * @return $this - */ - public function setTaxIdentificationNumber($taxIdentificationNumber) - { - $this->taxIdentificationNumber = $taxIdentificationNumber; - - return $this; - } - /** * @return Company */ diff --git a/src/Marello/Bundle/CustomerBundle/Form/Type/CompanyType.php b/src/Marello/Bundle/CustomerBundle/Form/Type/CompanyType.php index 87a4d20ac..63a062450 100644 --- a/src/Marello/Bundle/CustomerBundle/Form/Type/CompanyType.php +++ b/src/Marello/Bundle/CustomerBundle/Form/Type/CompanyType.php @@ -12,8 +12,6 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\Form\FormEvent; -use Symfony\Component\Form\FormEvents; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; @@ -58,6 +56,10 @@ public function buildForm(FormBuilderInterface $builder, array $options) 'label' => 'marello.customer.company.payment_term.label', 'required' => false, ]) + ->add('taxIdentificationNumber', TextType::class, [ + 'label' => 'marello.customer.company.tax_identification_number.label', + 'required' => false, + ]) ->add( 'appendCustomers', EntityIdentifierType::class, diff --git a/src/Marello/Bundle/CustomerBundle/Form/Type/CustomerType.php b/src/Marello/Bundle/CustomerBundle/Form/Type/CustomerType.php index b11a96c58..d1cb8c38d 100644 --- a/src/Marello/Bundle/CustomerBundle/Form/Type/CustomerType.php +++ b/src/Marello/Bundle/CustomerBundle/Form/Type/CustomerType.php @@ -42,9 +42,6 @@ public function buildForm(FormBuilderInterface $builder, array $options) ->add('email', EmailType::class, [ 'required' => true ]) - ->add('taxIdentificationNumber', TextType::class, [ - 'required' => false, - ]) ->add('primaryAddress', AddressType::class, [ 'required' => false, ]) diff --git a/src/Marello/Bundle/CustomerBundle/Migrations/Schema/MarelloCustomerBundleInstaller.php b/src/Marello/Bundle/CustomerBundle/Migrations/Schema/MarelloCustomerBundleInstaller.php index 41620e1fd..7cd0ce8db 100644 --- a/src/Marello/Bundle/CustomerBundle/Migrations/Schema/MarelloCustomerBundleInstaller.php +++ b/src/Marello/Bundle/CustomerBundle/Migrations/Schema/MarelloCustomerBundleInstaller.php @@ -34,7 +34,7 @@ class MarelloCustomerBundleInstaller implements */ public function getMigrationVersion() { - return 'v1_4_1'; + return 'v1_5'; } /** @@ -65,6 +65,7 @@ protected function createMarelloCompanyTable(Schema $schema) $table->addColumn('name', 'string', ['length' => 255]); $table->addColumn('company_number', 'string', ['length' => 255, 'notnull' => false]); $table->addColumn('payment_term_id', 'integer', ['notnull' => false]); + $table->addColumn('tax_identification_number', 'string', ['notnull' => false, 'length' => 255]); $table->addColumn('parent_id', 'integer', ['notnull' => false]); $table->addColumn('organization_id', 'integer', ['notnull' => false]); $table->addColumn('created_at', 'datetime'); @@ -103,7 +104,6 @@ protected function createMarelloCustomerTable(Schema $schema) $table->addColumn('last_name', 'string', ['length' => 255]); $table->addColumn('name_suffix', 'string', ['notnull' => false, 'length' => 255]); $table->addColumn('email', 'text', []); - $table->addColumn('tax_identification_number', 'string', ['notnull' => false, 'length' => 255]); $table->addColumn('company_id', 'integer', ['notnull' => false]); $table->setPrimaryKey(['id']); $table->addIndex(['organization_id']); diff --git a/src/Marello/Bundle/CustomerBundle/Migrations/Schema/v1_5/MarelloCustomerBundlePart1.php b/src/Marello/Bundle/CustomerBundle/Migrations/Schema/v1_5/MarelloCustomerBundlePart1.php new file mode 100644 index 000000000..904ebafe4 --- /dev/null +++ b/src/Marello/Bundle/CustomerBundle/Migrations/Schema/v1_5/MarelloCustomerBundlePart1.php @@ -0,0 +1,59 @@ +getTable(MarelloCustomerBundleInstaller::MARELLO_COMPANY_TABLE); + $table->addColumn('tax_identification_number', 'string', ['notnull' => false, 'length' => 255]); + if ($this->connection->getDriver()->getName() === DatabaseDriverInterface::DRIVER_POSTGRESQL) { + $sql = <<addPostQuery($sql); + } + + /** + * {@inheritdoc} + */ + public function setConnection(Connection $connection) + { + $this->connection = $connection; + } + +} diff --git a/src/Marello/Bundle/CustomerBundle/Migrations/Schema/v1_5/MarelloCustomerBundlePart2.php b/src/Marello/Bundle/CustomerBundle/Migrations/Schema/v1_5/MarelloCustomerBundlePart2.php new file mode 100644 index 000000000..3f2fb834e --- /dev/null +++ b/src/Marello/Bundle/CustomerBundle/Migrations/Schema/v1_5/MarelloCustomerBundlePart2.php @@ -0,0 +1,33 @@ +getTable(MarelloCustomerBundleInstaller::MARELLO_CUSTOMER_TABLE); + $table->dropColumn('tax_identification_number'); + } +} diff --git a/src/Marello/Bundle/CustomerBundle/Resources/config/services.yml b/src/Marello/Bundle/CustomerBundle/Resources/config/services.yml index bf043f992..de3a7c476 100644 --- a/src/Marello/Bundle/CustomerBundle/Resources/config/services.yml +++ b/src/Marello/Bundle/CustomerBundle/Resources/config/services.yml @@ -44,7 +44,7 @@ services: marello_customer.form.autocomplete.company_customer.search_handler: class: 'Marello\Bundle\CustomerBundle\Autocomplete\CompanyCustomerHandler' - parent: oro_form.autocomplete.search_handler + parent: oro_form.autocomplete.full_name.search_handler arguments: - 'Marello\Bundle\CustomerBundle\Entity\Customer' - ['namePrefix', 'firstName', 'middleName', 'lastName', 'nameSuffix'] diff --git a/src/Marello/Bundle/CustomerBundle/Resources/config/validation.yml b/src/Marello/Bundle/CustomerBundle/Resources/config/validation.yml index f193a3d9b..9bc7c6904 100644 --- a/src/Marello/Bundle/CustomerBundle/Resources/config/validation.yml +++ b/src/Marello/Bundle/CustomerBundle/Resources/config/validation.yml @@ -15,4 +15,4 @@ Marello\Bundle\CustomerBundle\Entity\Company: message: 'marello.customer.company.number.message' properties: name: - - NotBlank: ~ \ No newline at end of file + - NotBlank: ~ diff --git a/src/Marello/Bundle/CustomerBundle/Resources/translations/messages.en.yml b/src/Marello/Bundle/CustomerBundle/Resources/translations/messages.en.yml index bffdb9031..57e808fb5 100644 --- a/src/Marello/Bundle/CustomerBundle/Resources/translations/messages.en.yml +++ b/src/Marello/Bundle/CustomerBundle/Resources/translations/messages.en.yml @@ -7,7 +7,6 @@ marello: organization.label: 'Organization' primary_address.label: 'Primary Address' shipping_address.label: 'Shipping Address' - tax_identification_number.label: 'Tax Identification Number' addresses.label: 'Addresses' email.label: 'Primary Email' emails.label: 'Email Addresses' @@ -35,6 +34,7 @@ marello: customers.label: 'Customers' organization.label: 'Organization' payment_term.label: 'Payment Term' + tax_identification_number.label: 'Tax Identification Number' form: choose: 'Choose a company...' diff --git a/src/Marello/Bundle/CustomerBundle/Resources/translations/pdf.en.yml b/src/Marello/Bundle/CustomerBundle/Resources/translations/pdf.en.yml index da88d9569..44fa83ae6 100644 --- a/src/Marello/Bundle/CustomerBundle/Resources/translations/pdf.en.yml +++ b/src/Marello/Bundle/CustomerBundle/Resources/translations/pdf.en.yml @@ -3,3 +3,4 @@ marello: company: pdf: company_number.label: "Company Number" + tax_identification_number.label: 'Tax Identification Number' \ No newline at end of file diff --git a/src/Marello/Bundle/CustomerBundle/Resources/views/Company/update.html.twig b/src/Marello/Bundle/CustomerBundle/Resources/views/Company/update.html.twig index 360527cdc..0222c29df 100644 --- a/src/Marello/Bundle/CustomerBundle/Resources/views/Company/update.html.twig +++ b/src/Marello/Bundle/CustomerBundle/Resources/views/Company/update.html.twig @@ -54,6 +54,7 @@ form_row(form.companyNumber), form_row(form.parent), form_row(form.paymentTerm), + form_row(form.taxIdentificationNumber), form_widget(form.appendCustomers, {'id': 'appendCustomers'}), form_widget(form.removeCustomers, {'id': 'removeCustomers'}), ] diff --git a/src/Marello/Bundle/CustomerBundle/Resources/views/Company/view.html.twig b/src/Marello/Bundle/CustomerBundle/Resources/views/Company/view.html.twig index c7f2e79b1..5dd7494bf 100644 --- a/src/Marello/Bundle/CustomerBundle/Resources/views/Company/view.html.twig +++ b/src/Marello/Bundle/CustomerBundle/Resources/views/Company/view.html.twig @@ -35,6 +35,7 @@ {% if entity.paymentTerm %} {{ UI.renderProperty('marello.customer.company.payment_term.label'|trans, entity.paymentTerm.labels|localized_value) }} {% endif %} + {{ UI.renderProperty('marello.customer.company.tax_identification_number.label'|trans, entity.taxIdentificationNumber ? entity.taxIdentificationNumber : 'N/A') }} {{ entityConfig.renderDynamicFields(entity) }} diff --git a/src/Marello/Bundle/CustomerBundle/Resources/views/Customer/update.html.twig b/src/Marello/Bundle/CustomerBundle/Resources/views/Customer/update.html.twig index 6f2925943..d7826acec 100644 --- a/src/Marello/Bundle/CustomerBundle/Resources/views/Customer/update.html.twig +++ b/src/Marello/Bundle/CustomerBundle/Resources/views/Customer/update.html.twig @@ -49,7 +49,6 @@ form_row(form.lastName), form_row(form.nameSuffix), form_row(form.email), - form_row(form.taxIdentificationNumber), ] }] }] %} diff --git a/src/Marello/Bundle/CustomerBundle/Tests/Functional/Api/responses/cget_companies_list.yml b/src/Marello/Bundle/CustomerBundle/Tests/Functional/Api/responses/cget_companies_list.yml index 8e5ffd244..a25e947aa 100644 --- a/src/Marello/Bundle/CustomerBundle/Tests/Functional/Api/responses/cget_companies_list.yml +++ b/src/Marello/Bundle/CustomerBundle/Tests/Functional/Api/responses/cget_companies_list.yml @@ -4,6 +4,7 @@ data: id: 'id)>' attributes: name: company1 + taxIdentificationNumber: null relationships: customers: data: @@ -22,6 +23,7 @@ data: id: 'id)>' attributes: name: company2 + taxIdentificationNumber: null relationships: paymentTerm: data: @@ -44,6 +46,7 @@ data: id: 'id)>' attributes: name: company3 + taxIdentificationNumber: null relationships: customers: data: diff --git a/src/Marello/Bundle/CustomerBundle/Tests/Functional/Api/responses/cget_customer_list.yml b/src/Marello/Bundle/CustomerBundle/Tests/Functional/Api/responses/cget_customer_list.yml index 3901a01b4..13a853953 100644 --- a/src/Marello/Bundle/CustomerBundle/Tests/Functional/Api/responses/cget_customer_list.yml +++ b/src/Marello/Bundle/CustomerBundle/Tests/Functional/Api/responses/cget_customer_list.yml @@ -3,7 +3,6 @@ data: type: marellocustomers id: 'id)>' attributes: - taxIdentificationNumber: null namePrefix: null firstName: Marilyn middleName: null @@ -30,7 +29,6 @@ data: type: marellocustomers id: 'id)>' attributes: - taxIdentificationNumber: null namePrefix: null firstName: James middleName: null @@ -57,7 +55,6 @@ data: type: marellocustomers id: 'id)>' attributes: - taxIdentificationNumber: null namePrefix: null firstName: Randy middleName: null @@ -84,7 +81,6 @@ data: type: marellocustomers id: 'id)>' attributes: - taxIdentificationNumber: null namePrefix: null firstName: Priscilla middleName: null @@ -111,7 +107,6 @@ data: type: marellocustomers id: 'id)>' attributes: - taxIdentificationNumber: null namePrefix: null firstName: May middleName: null @@ -138,7 +133,6 @@ data: type: marellocustomers id: 'id)>' attributes: - taxIdentificationNumber: null namePrefix: null firstName: Catherine middleName: null @@ -165,7 +159,6 @@ data: type: marellocustomers id: 'id)>' attributes: - taxIdentificationNumber: null namePrefix: null firstName: Richard middleName: null @@ -192,7 +185,6 @@ data: type: marellocustomers id: 'id)>' attributes: - taxIdentificationNumber: null namePrefix: null firstName: Edward middleName: null @@ -219,7 +211,6 @@ data: type: marellocustomers id: 'id)>' attributes: - taxIdentificationNumber: null namePrefix: null firstName: Kelly middleName: null @@ -246,7 +237,6 @@ data: type: marellocustomers id: 'id)>' attributes: - taxIdentificationNumber: null namePrefix: null firstName: Roberta middleName: null diff --git a/src/Marello/Bundle/CustomerBundle/Tests/Functional/Api/responses/get_company_by_id.yml b/src/Marello/Bundle/CustomerBundle/Tests/Functional/Api/responses/get_company_by_id.yml index 7ed038fe3..4754171e1 100644 --- a/src/Marello/Bundle/CustomerBundle/Tests/Functional/Api/responses/get_company_by_id.yml +++ b/src/Marello/Bundle/CustomerBundle/Tests/Functional/Api/responses/get_company_by_id.yml @@ -3,6 +3,7 @@ data: id: 'id)>' attributes: name: company1 + taxIdentificationNumber: null relationships: customers: data: diff --git a/src/Marello/Bundle/CustomerBundle/Tests/Functional/Api/responses/get_customer_by_email.yml b/src/Marello/Bundle/CustomerBundle/Tests/Functional/Api/responses/get_customer_by_email.yml index a73d6952b..02bc3d8e1 100644 --- a/src/Marello/Bundle/CustomerBundle/Tests/Functional/Api/responses/get_customer_by_email.yml +++ b/src/Marello/Bundle/CustomerBundle/Tests/Functional/Api/responses/get_customer_by_email.yml @@ -3,7 +3,6 @@ data: type: marellocustomers id: 'id)>' attributes: - taxIdentificationNumber: null namePrefix: null firstName: James middleName: null diff --git a/src/Marello/Bundle/CustomerBundle/Tests/Functional/Api/responses/get_customer_by_id.yml b/src/Marello/Bundle/CustomerBundle/Tests/Functional/Api/responses/get_customer_by_id.yml index fe9805cb6..44b291a12 100644 --- a/src/Marello/Bundle/CustomerBundle/Tests/Functional/Api/responses/get_customer_by_id.yml +++ b/src/Marello/Bundle/CustomerBundle/Tests/Functional/Api/responses/get_customer_by_id.yml @@ -2,7 +2,6 @@ data: type: marellocustomers id: 'id)>' attributes: - taxIdentificationNumber: null namePrefix: null firstName: James middleName: null diff --git a/src/Marello/Bundle/CustomerBundle/Tests/Unit/Autocomplete/ParentCompanySearchHandlerTest.php b/src/Marello/Bundle/CustomerBundle/Tests/Unit/Autocomplete/ParentCompanySearchHandlerTest.php index 6aef4d9ee..4e94db197 100644 --- a/src/Marello/Bundle/CustomerBundle/Tests/Unit/Autocomplete/ParentCompanySearchHandlerTest.php +++ b/src/Marello/Bundle/CustomerBundle/Tests/Unit/Autocomplete/ParentCompanySearchHandlerTest.php @@ -337,10 +337,6 @@ protected function assertSearchCall( $queryBuilder->expects($this->once()) ->method('getQuery') ->will($this->returnValue($query)); - $this->aclHelper->expects($this->once()) - ->method('apply') - ->with($query) - ->will($this->returnValue($query)); $this->entityRepository ->expects($this->any()) ->method('createQueryBuilder') diff --git a/src/Marello/Bundle/DataGridBundle/Extension/Totals/OrmTotalsExtension.php b/src/Marello/Bundle/DataGridBundle/Extension/Totals/OrmTotalsExtension.php new file mode 100644 index 000000000..2aae85c53 --- /dev/null +++ b/src/Marello/Bundle/DataGridBundle/Extension/Totals/OrmTotalsExtension.php @@ -0,0 +1,93 @@ + $total) { + $column = []; + if (isset($data[$field])) { + $totalValue = $data[$field]; + if (isset($total[Configuration::TOTALS_DIVISOR_KEY])) { + $divisor = (int) $total[Configuration::TOTALS_DIVISOR_KEY]; + if ($divisor != 0) { + $totalValue = $totalValue / $divisor; + } + } + if (isset($total[Configuration::TOTALS_FORMATTER_KEY])) { + if ($total[Configuration::TOTALS_FORMATTER_KEY] === 'currency' && isset($data['currency'])) { + $totalValue = $this->applyFrontendFormatting( + [$totalValue, $data['currency']], + $total[Configuration::TOTALS_FORMATTER_KEY] + ); + } else { + $totalValue = $this->applyFrontendFormatting( + $totalValue, + $total[Configuration::TOTALS_FORMATTER_KEY] + ); + } + } + $column['total'] = $totalValue; + } + if (isset($total[Configuration::TOTALS_LABEL_KEY])) { + $column[Configuration::TOTALS_LABEL_KEY] = + $this->translator->trans($total[Configuration::TOTALS_LABEL_KEY]); + } + $columns[$field] = $column; + }; + + return ['columns' => $columns]; + } + + /** + * {@inheritDoc} + */ + protected function applyFrontendFormatting($val = null, $formatter = null) + { + if (null === $formatter) { + return $val; + } + + switch ($formatter) { + case PropertyInterface::TYPE_DATE: + $val = $this->dateTimeFormatter->formatDate($val); + break; + case PropertyInterface::TYPE_DATETIME: + $val = $this->dateTimeFormatter->format($val); + break; + case PropertyInterface::TYPE_TIME: + $val = $this->dateTimeFormatter->formatTime($val); + break; + case PropertyInterface::TYPE_DECIMAL: + $val = $this->numberFormatter->formatDecimal($val); + break; + case PropertyInterface::TYPE_INTEGER: + $val = $this->numberFormatter->formatDecimal($val); + break; + case PropertyInterface::TYPE_PERCENT: + $val = $this->numberFormatter->formatPercent($val); + break; + case PropertyInterface::TYPE_CURRENCY: + $val = is_array($val) ? + $this->numberFormatter->formatCurrency($val[0], $val[1]) : + $this->numberFormatter->formatCurrency($val); + break; + } + + return $val; + } +} diff --git a/src/Marello/Bundle/DataGridBundle/Resources/config/services.yml b/src/Marello/Bundle/DataGridBundle/Resources/config/services.yml index 9ca7fb00c..d0b491e69 100644 --- a/src/Marello/Bundle/DataGridBundle/Resources/config/services.yml +++ b/src/Marello/Bundle/DataGridBundle/Resources/config/services.yml @@ -6,4 +6,15 @@ services: class: 'Marello\Bundle\DataGridBundle\EventListener\Datagrid\RowSelectionSelectAllListener' tags: - { name: kernel.event_listener, event: oro_datagrid.datagrid.build.after, method: onBuildAfter, priority: 250 } - - { name: kernel.event_listener, event: oro_datagrid.orm_datasource.result.after, method: onResultAfter } \ No newline at end of file + - { name: kernel.event_listener, event: oro_datagrid.orm_datasource.result.after, method: onResultAfter } + + marello_datagrid.extension.totals: + class: 'Marello\Bundle\DataGridBundle\Extension\Totals\OrmTotalsExtension' + decorates: oro_datagrid.extension.totals + arguments: + - '@translator' + - '@oro_locale.formatter.number' + - '@oro_locale.formatter.date_time' + - '@oro_security.acl_helper' + tags: + - { name: oro_datagrid.extension } diff --git a/src/Marello/Bundle/DemoDataBundle/Migrations/Data/Demo/ORM/LoadProductData.php b/src/Marello/Bundle/DemoDataBundle/Migrations/Data/Demo/ORM/LoadProductData.php index b6bfa942b..575d87d3f 100644 --- a/src/Marello/Bundle/DemoDataBundle/Migrations/Data/Demo/ORM/LoadProductData.php +++ b/src/Marello/Bundle/DemoDataBundle/Migrations/Data/Demo/ORM/LoadProductData.php @@ -5,8 +5,8 @@ use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\DependentFixtureInterface; use Doctrine\Common\Persistence\ObjectManager; +use Marello\Bundle\ProductBundle\Entity\Builder\ProductFamilyBuilder; use Marello\Bundle\ProductBundle\Entity\Product; -use Marello\Bundle\ProductBundle\Migrations\Data\ORM\LoadDefaultAttributeFamilyData; use Marello\Bundle\SalesBundle\Entity\SalesChannel; use Oro\Bundle\EntityConfigBundle\Attribute\Entity\AttributeFamily; use Oro\Bundle\LocaleBundle\Entity\LocalizedFallbackValue; @@ -127,7 +127,7 @@ private function createProduct(array $data) /** @var AttributeFamily $attributeFamily */ $attributeFamily = $this->manager ->getRepository(AttributeFamily::class) - ->findOneByCode(LoadDefaultAttributeFamilyData::DEFAULT_FAMILY_CODE); + ->findOneByCode(ProductFamilyBuilder::DEFAULT_FAMILY_CODE); $product->setAttributeFamily($attributeFamily); return $product; diff --git a/src/Marello/Bundle/DemoDataBundle/Migrations/Data/Demo/ORM/LoadProductImageData.php b/src/Marello/Bundle/DemoDataBundle/Migrations/Data/Demo/ORM/LoadProductImageData.php index 72ab3ecf7..90b62718c 100644 --- a/src/Marello/Bundle/DemoDataBundle/Migrations/Data/Demo/ORM/LoadProductImageData.php +++ b/src/Marello/Bundle/DemoDataBundle/Migrations/Data/Demo/ORM/LoadProductImageData.php @@ -79,7 +79,7 @@ public function loadProductImages() } /** - * @param $sku + * @param $sku * @return null */ protected function getProductImage($sku) @@ -87,13 +87,15 @@ protected function getProductImage($sku) try { $imagePath = $this->getImagePath($sku); $fileManager = $this->container->get('oro_attachment.file_manager'); - $image = $fileManager->createFileEntity($imagePath); - if ($image) { - $this->manager->persist($image); - $image->setOwner($this->adminUser); - } + if ($imagePath) { + $image = $fileManager->createFileEntity($imagePath); + if ($image) { + $this->manager->persist($image); + $image->setOwner($this->adminUser); + } - return $image; + return $image; + } } catch (\Exception $e) { //image not found } diff --git a/src/Marello/Bundle/FilterBundle/DependencyInjection/MarelloFilterExtension.php b/src/Marello/Bundle/FilterBundle/DependencyInjection/MarelloFilterExtension.php new file mode 100644 index 000000000..34a3ea6b7 --- /dev/null +++ b/src/Marello/Bundle/FilterBundle/DependencyInjection/MarelloFilterExtension.php @@ -0,0 +1,26 @@ +load('services.yml'); + } +} diff --git a/src/Marello/Bundle/FilterBundle/Filter/ChoiceLikeFilter.php b/src/Marello/Bundle/FilterBundle/Filter/ChoiceLikeFilter.php new file mode 100644 index 000000000..4238cd266 --- /dev/null +++ b/src/Marello/Bundle/FilterBundle/Filter/ChoiceLikeFilter.php @@ -0,0 +1,52 @@ +getQueryBuilder(); + $parameter = $qb->getParameter($parameterName); + $value = $parameter->getValue(); + if (is_array($value)) { + $comparisonExpressions = []; + foreach ($value as $key => $valueItem) { + if ($key !== 0) { + $parameterName = sprintf('%s%d', $parameterName, $key); + } + $qb->setParameter($parameterName, '%|' . $valueItem . '|%'); + switch ($comparisonType) { + case ChoiceFilterType::TYPE_NOT_CONTAINS: + $comparisonExpressions[] = $ds->expr()->notLike($fieldName, $parameterName, true); + break; + default: + $comparisonExpressions[] = $ds->expr()->like($fieldName, $parameterName, true); + } + } + + return call_user_func_array([$ds->expr(), 'andX'], $comparisonExpressions); + } else { + switch ($comparisonType) { + case ChoiceFilterType::TYPE_NOT_CONTAINS: + return $ds->expr()->notLike($fieldName, $parameterName, true); + default: + return $ds->expr()->like($fieldName, $parameterName, true); + } + } + } +} diff --git a/src/Marello/Bundle/FilterBundle/Resources/config/services.yml b/src/Marello/Bundle/FilterBundle/Resources/config/services.yml new file mode 100644 index 000000000..74f91ae18 --- /dev/null +++ b/src/Marello/Bundle/FilterBundle/Resources/config/services.yml @@ -0,0 +1,9 @@ +services: + marello_filter.choice_like_filter: + class: Marello\Bundle\FilterBundle\Filter\ChoiceLikeFilter + public: false + arguments: + - '@form.factory' + - '@oro_filter.filter_utility' + tags: + - { name: oro_filter.extension.orm_filter.filter, type: choice_like } diff --git a/src/Marello/Bundle/InventoryBundle/Controller/InventoryLevelController.php b/src/Marello/Bundle/InventoryBundle/Controller/InventoryLevelController.php index e9c4c3428..7b08946c7 100644 --- a/src/Marello/Bundle/InventoryBundle/Controller/InventoryLevelController.php +++ b/src/Marello/Bundle/InventoryBundle/Controller/InventoryLevelController.php @@ -115,4 +115,23 @@ public function manageBatchesAction(InventoryLevel $inventoryLevel, Request $req $request ); } + + /** + * @Route( + * path="/manage-batches/view/{id}", + * requirements={"id"="\d+"}, + * name="marello_inventory_inventorylevel_batches_view" + * ) + * @Template("MarelloInventoryBundle:InventoryLevel:batchesView.html.twig") + * + * @param InventoryLevel $inventoryLevel + * + * @return array + */ + public function viewAction(InventoryLevel $inventoryLevel) + { + return [ + 'entity' => $inventoryLevel + ]; + } } diff --git a/src/Marello/Bundle/InventoryBundle/Entity/InventoryBatch.php b/src/Marello/Bundle/InventoryBundle/Entity/InventoryBatch.php index 3968d7f2c..dccf9f59c 100644 --- a/src/Marello/Bundle/InventoryBundle/Entity/InventoryBatch.php +++ b/src/Marello/Bundle/InventoryBundle/Entity/InventoryBatch.php @@ -14,9 +14,6 @@ /** * @ORM\Entity() * @Oro\Config( - * routeView="marello_inventory_batch_view", - * routeName="marello_inventory_batch_index", - * routeCreate="marello_inventory_batch_create", * defaultValues={ * "entity"={ * "icon"="fa-cubes" diff --git a/src/Marello/Bundle/InventoryBundle/Entity/InventoryLevelLogRecord.php b/src/Marello/Bundle/InventoryBundle/Entity/InventoryLevelLogRecord.php index da464135b..a710028a8 100644 --- a/src/Marello/Bundle/InventoryBundle/Entity/InventoryLevelLogRecord.php +++ b/src/Marello/Bundle/InventoryBundle/Entity/InventoryLevelLogRecord.php @@ -38,7 +38,7 @@ class InventoryLevelLogRecord /** * @ORM\ManyToOne(targetEntity="Marello\Bundle\InventoryBundle\Entity\InventoryLevel") - * @ORM\JoinColumn(name="inventory_level_id", referencedColumnName="id") + * @ORM\JoinColumn(name="inventory_level_id", referencedColumnName="id", onDelete="SET NULL") * @Oro\ConfigField( * defaultValues={ * "entity"={ @@ -57,7 +57,7 @@ class InventoryLevelLogRecord /** * @ORM\ManyToOne(targetEntity="Marello\Bundle\InventoryBundle\Entity\InventoryItem", * cascade={"persist", "remove"}) - * @ORM\JoinColumn(name="inventory_item_id", referencedColumnName="id", onDelete="CASCADE") + * @ORM\JoinColumn(name="inventory_item_id", referencedColumnName="id", onDelete="CASCADE", nullable=false) * @Oro\ConfigField( * defaultValues={ * "entity"={ diff --git a/src/Marello/Bundle/InventoryBundle/EventListener/Datagrid/InventoryLevelGridListener.php b/src/Marello/Bundle/InventoryBundle/EventListener/Datagrid/InventoryLevelGridListener.php new file mode 100644 index 000000000..36c4b6c13 --- /dev/null +++ b/src/Marello/Bundle/InventoryBundle/EventListener/Datagrid/InventoryLevelGridListener.php @@ -0,0 +1,68 @@ +doctrineHelper = $helper; + } + + /** + * @param BuildBefore $event + */ + public function onBuildBefore(BuildBefore $event) + { + $inventoryItemId = $this->getParameter($event->getDatagrid(), 'inventoryItemId'); + /** @var InventoryItem $inventoryItem */ + $inventoryItem = $this->doctrineHelper + ->getEntityRepositoryForClass(InventoryItem::class) + ->find($inventoryItemId); + if ($inventoryItem->isEnableBatchInventory()) { + $config = $event->getConfig(); + $columns = $config->offsetGetByPath('[columns]'); + $columns = array_merge( + $columns, + [ + 'manageBatches' => [ + 'label' => 'marello.inventory.inventorylevel.grid.batches.label', + 'type' => 'twig', + 'frontend_type' => 'html', + 'template' => 'MarelloInventoryBundle:Inventory/Datagrid:manageBatches.html.twig', + ] + ] + ); + $config->offsetSetByPath('[columns]', $columns); + } + } + + /** + * @param DatagridInterface $datagrid + * @param string $parameterName + * @return mixed + */ + protected function getParameter(DatagridInterface $datagrid, $parameterName) + { + $value = $datagrid->getParameters()->get($parameterName); + + if ($value === null) { + throw new \LogicException(sprintf('Parameter "%s" must be set', $parameterName)); + } + + return $value; + } +} diff --git a/src/Marello/Bundle/InventoryBundle/Form/Type/InventoryBatchType.php b/src/Marello/Bundle/InventoryBundle/Form/Type/InventoryBatchType.php index 8e3419cc0..c98608e50 100644 --- a/src/Marello/Bundle/InventoryBundle/Form/Type/InventoryBatchType.php +++ b/src/Marello/Bundle/InventoryBundle/Form/Type/InventoryBatchType.php @@ -76,6 +76,13 @@ public function buildForm(FormBuilderInterface $builder, array $options) 'disabled' => true ] ) + ->add( + 'deliveryDate', + OroDateType::class, + [ + 'required' => false + ] + ) ->add( 'purchasePrice', NumberType::class, diff --git a/src/Marello/Bundle/InventoryBundle/ImportExport/Strategy/InventoryLevelUpdateStrategy.php b/src/Marello/Bundle/InventoryBundle/ImportExport/Strategy/InventoryLevelUpdateStrategy.php index e440ea43d..c09621acc 100644 --- a/src/Marello/Bundle/InventoryBundle/ImportExport/Strategy/InventoryLevelUpdateStrategy.php +++ b/src/Marello/Bundle/InventoryBundle/ImportExport/Strategy/InventoryLevelUpdateStrategy.php @@ -253,7 +253,13 @@ protected function findInventoryBatch(InventoryBatch $entity) protected function getProduct($entity) { return $this->databaseHelper - ->findOneBy(Product::class, ['sku' => $entity->getInventoryItem()->getProduct()->getSku()]); + ->findOneBy( + Product::class, + [ + 'sku' => $entity->getInventoryItem()->getProduct()->getSku(), + 'organization' => $entity->getOrganization() + ] + ); } /** diff --git a/src/Marello/Bundle/InventoryBundle/Migrations/Schema/MarelloInventoryBundleInstaller.php b/src/Marello/Bundle/InventoryBundle/Migrations/Schema/MarelloInventoryBundleInstaller.php index 554d7b846..818dbce7e 100644 --- a/src/Marello/Bundle/InventoryBundle/Migrations/Schema/MarelloInventoryBundleInstaller.php +++ b/src/Marello/Bundle/InventoryBundle/Migrations/Schema/MarelloInventoryBundleInstaller.php @@ -178,6 +178,7 @@ protected function createMarelloInventoryInventoryLogLevelTable(Schema $schema) $table->addColumn('warehouse_name', 'string', ['notnull' => true, 'length' => 255]); $table->setPrimaryKey(['id']); $table->addIndex(['inventory_item_id']); + $table->addIndex(['inventory_level_id']); $table->addIndex(['user_id'], 'IDX_32D13BA4F675F31B', []); } @@ -374,6 +375,12 @@ protected function addMarelloInventoryInventoryLevelLogForeignKeys(Schema $schem ['id'], ['onDelete' => 'CASCADE', 'onUpdate' => null] ); + $table->addForeignKeyConstraint( + $schema->getTable('marello_inventory_level'), + ['inventory_level_id'], + ['id'], + ['onDelete' => 'SET NULL', 'onUpdate' => null] + ); $table->addForeignKeyConstraint( $schema->getTable('oro_user'), ['user_id'], diff --git a/src/Marello/Bundle/InventoryBundle/Migrations/Schema/v2_5/UpdateInventoryLevelLogForeignKey.php b/src/Marello/Bundle/InventoryBundle/Migrations/Schema/v2_5/UpdateInventoryLevelLogForeignKey.php new file mode 100644 index 000000000..e74871fc2 --- /dev/null +++ b/src/Marello/Bundle/InventoryBundle/Migrations/Schema/v2_5/UpdateInventoryLevelLogForeignKey.php @@ -0,0 +1,41 @@ +updateInventoryLevelLogForeignKeyConstraint($schema, $queries); + } + + /** + * {@inheritdoc} + * @param Schema $schema + * @param QueryBag $queries + * @throws \Doctrine\DBAL\Schema\SchemaException + */ + protected function updateInventoryLevelLogForeignKeyConstraint(Schema $schema, $queries) + { + $table = $schema->getTable(self::INVENTORY_LEVEL_LOG_TABLE_NAME); + $table->addIndex(['inventory_level_id']); + $table->addForeignKeyConstraint( + $schema->getTable(self::INVENTORY_LEVEL_TABLE_NAME), + ['inventory_level_id'], + ['id'], + ['onDelete' => 'SET NULL', 'onUpdate' => null] + ); + } +} diff --git a/src/Marello/Bundle/InventoryBundle/Resources/config/eventlistener.yml b/src/Marello/Bundle/InventoryBundle/Resources/config/eventlistener.yml index 494fbd959..81f28de56 100644 --- a/src/Marello/Bundle/InventoryBundle/Resources/config/eventlistener.yml +++ b/src/Marello/Bundle/InventoryBundle/Resources/config/eventlistener.yml @@ -99,3 +99,10 @@ services: - { name: doctrine.orm.entity_listener, entity: 'Marello\Bundle\InventoryBundle\Entity\InventoryItem', event: postPersist } - { name: doctrine.orm.entity_listener, entity: 'Marello\Bundle\InventoryBundle\Entity\InventoryItem', event: preUpdate } - { name: doctrine.event_listener, event: postFlush } + + marello_inventory.event_listener.datagrid.inventory_level_grid: + class: 'Marello\Bundle\InventoryBundle\EventListener\Datagrid\InventoryLevelGridListener' + arguments: + - '@oro_entity.doctrine_helper' + tags: + - { name: kernel.event_listener, event: oro_datagrid.datagrid.build.before.marello-inventory-levels, method: onBuildBefore } \ No newline at end of file diff --git a/src/Marello/Bundle/InventoryBundle/Resources/config/oro/datagrids.yml b/src/Marello/Bundle/InventoryBundle/Resources/config/oro/datagrids.yml index 89595beae..50548077f 100644 --- a/src/Marello/Bundle/InventoryBundle/Resources/config/oro/datagrids.yml +++ b/src/Marello/Bundle/InventoryBundle/Resources/config/oro/datagrids.yml @@ -6,7 +6,6 @@ datagrids: query: select: - i.id - - p.denormalizedDefaultName as productName - p.sku as productSku - i.enableBatchInventory as enableBatchInventory - pu.name as productUnit @@ -30,8 +29,6 @@ datagrids: template: MarelloProductBundle:Product/Datagrid:productSku.html.twig productName: label: marello.product.names.label - frontend_type: string - data_name: productName productUnit: label: marello.inventory.inventoryitem.product_unit.label frontend_type: string @@ -55,7 +52,7 @@ datagrids: sorters: columns: productSku: { data_name: p.sku } - productName: { data_name: p.denormalizedDefaultName } + productName: { data_name: productName } productUnit: { data_name: productUnit } enableBatchInventory: { data_name: enableBatchInventory } inventoryQty: { data_name: inventoryQty } @@ -70,7 +67,7 @@ datagrids: data_name: p.sku productName: type: string - data_name: p.denormalizedDefaultName + data_name: productName productUnit: type: enum data_name: productUnit @@ -92,6 +89,9 @@ datagrids: filter_by_having: true properties: id: ~ + productName: + type: localized_value + data_name: p.names inventory_view_link: type: url route: marello_inventory_inventory_view @@ -211,6 +211,7 @@ datagrids: - il.updatedAt - wht.label as warehouseTypeLabel - wh.label as warehouse + - wh.code as warehouseCode - COALESCE(il.inventory, 0) AS inventoryQty - COALESCE(il.allocatedInventory, 0) AS allocatedInventoryQty - COALESCE(il.inventory - il.allocatedInventory, 0) AS virtualInventoryQty @@ -223,19 +224,23 @@ datagrids: where: and: - IDENTITY(il.inventoryItem) = :inventoryItemId - groupBy: il.id, wh.label, wht.label + groupBy: il.id, wh.code, wh.label, wht.label bind_parameters: inventoryItemId: inventoryItemId columns: warehouse: label: marello.inventory.inventorylevel.warehouse.label frontend_type: string + warehouseCode: + label: marello.inventory.inventorylevel.grid.warehouse_code.label + frontend_type: string pickLocation: label: marello.inventory.inventorylevel.pick_location.label frontend_type: string warehouseTypeLabel: label: marello.inventory.warehousetype.entity_label frontend_type: string + renderable: false inventoryQty: label: marello.inventory.inventorylevel.inventory.label frontend_type: number @@ -248,9 +253,18 @@ datagrids: label: marello.inventory.inventorylevel.virtual_inventory.label frontend_type: number data_name: virtualInventoryQty - updatedAt: - label: oro.ui.updated_at - frontend_type: datetime + filters: + columns: + warehouse: + type: string + data_name: warehouse + warehouseCode: + type: string + data_name: warehouseCode + warehouseTypeLabel: + type: string + data_name: warehouseTypeLabel + enabled: false marello-balanced-inventory-levels-grid: extended_entity_name: Marello\Bundle\InventoryBundle\Entity\BalancedInventoryLevel @@ -259,7 +273,6 @@ datagrids: query: select: - balancedInventoryLevel - - p.denormalizedDefaultName as productName - p.sku as productSku - scg.name as salesChannelGroupName from: @@ -277,8 +290,6 @@ datagrids: template: MarelloProductBundle:Product/Datagrid:productSku.html.twig productName: label: marello.product.names.label - frontend_type: string - data_name: productName inventoryQty: label: marello.inventory.balancedinventorylevel.inventory.label frontend_type: integer @@ -346,3 +357,50 @@ datagrids: data_name: balancedInventoryLevel.reservedInventory default: productName: 'DESC' + properties: + productName: + type: localized_value + data_name: p.names + + marello-inventory-batches: + extended_entity_name: Marello\Bundle\InventoryBundle\Entity\InventoryBatch + source: + type: orm + query: + select: + - ib + from: + - { table: MarelloInventoryBundle:InventoryBatch, alias: ib } + where: + and: + - IDENTITY(ib.inventoryLevel) = :inventoryLevelId + bind_parameters: + inventoryLevelId: inventoryLevelId + columns: + batchNumber: + label: marello.inventory.inventorybatch.batch_number.label + frontend_type: string + data_name: batchNumber + quantity: + label: marello.inventory.inventorybatch.quantity.label + frontend_type: integer + data_name: quantity + receivedDate: + label: marello.inventory.inventorybatch.date_received.label + frontend_type: datetime + data_name: deliveryDate + expirationDate: + label: marello.inventory.inventorybatch.expiration_date.label + frontend_type: datetime + data_name: expirationDate + purchasePrice: + label: marello.inventory.inventorybatch.purchase_price.label + frontend_type: currency + data_name: purchasePrice + options: + export: false + mass_actions: ~ + toolbarOptions: + hide: true + pagination: + hide: true \ No newline at end of file diff --git a/src/Marello/Bundle/InventoryBundle/Resources/public/css/scss/main.scss b/src/Marello/Bundle/InventoryBundle/Resources/public/css/scss/main.scss index 0f2612614..0c0477af9 100644 --- a/src/Marello/Bundle/InventoryBundle/Resources/public/css/scss/main.scss +++ b/src/Marello/Bundle/InventoryBundle/Resources/public/css/scss/main.scss @@ -16,7 +16,7 @@ .inventorylevel-warehouse { .select2-container { - width: 190px; + width: 300px; .select2-choice { .select2-arrow { @@ -30,7 +30,7 @@ } } -.inventorylevel-adjustment { +.inventorylevel-adjustment, .inventorybatch-adjustment { .selector { width: 100px !important; @@ -48,6 +48,12 @@ } } +.inventorybatch-delivery-date, .inventorybatch-purchase-price, .inventorybatch-expiration-date { + input[type=text] { + width: 100px !important; + } +} + // Font Awesome .fa-caret-down:before { content: "\f0d7"; diff --git a/src/Marello/Bundle/InventoryBundle/Resources/translations/messages.en.yml b/src/Marello/Bundle/InventoryBundle/Resources/translations/messages.en.yml index cdf44347d..0eebca7b5 100644 --- a/src/Marello/Bundle/InventoryBundle/Resources/translations/messages.en.yml +++ b/src/Marello/Bundle/InventoryBundle/Resources/translations/messages.en.yml @@ -108,6 +108,11 @@ marello: pick_location.label: Pick Location inventory_batches.label: Inventory Batches + grid: + warehouse_code.label: Warehouse Code + batches.label: Batches + view_batches.label: View Batches + form: manage_batches.label: Manage Batches @@ -120,11 +125,12 @@ marello: batch_reference.label: Batch Reference purchase_reference.label: Purchase Reference quantity.label: Quantity - delivery_date.label: Delivery Date + date_received.label: Date Received expiration_date.label: Expiration Date purchase_price.label: Purchase Price total_price.label: Total Price organization.label: Organization + delivery_date.label: Delivery Date inventorylevellogrecord: id.label: Id diff --git a/src/Marello/Bundle/InventoryBundle/Resources/views/Form/fields.html.twig b/src/Marello/Bundle/InventoryBundle/Resources/views/Form/fields.html.twig index 47124c3be..613f4e6d7 100644 --- a/src/Marello/Bundle/InventoryBundle/Resources/views/Form/fields.html.twig +++ b/src/Marello/Bundle/InventoryBundle/Resources/views/Form/fields.html.twig @@ -108,7 +108,7 @@ -
+
@@ -118,14 +118,20 @@ {{ form_errors(form.adjustmentQuantity) }}
- -
+ +
+ {{ form_widget(form.deliveryDate) }} +
+ {{ form_errors(form.deliveryDate) }} + + +
{{ form_widget(form.purchasePrice) }}
{{ form_errors(form.purchasePrice) }} - -
+ +
{{ form_widget(form.expirationDate) }}
{{ form_errors(form.expirationDate) }} @@ -172,6 +178,7 @@ {{ 'marello.inventory.inventorybatch.batch_number.label'|trans }} {{ 'marello.inventory.inventorybatch.quantity.label'|trans }} {{ 'marello.inventory.model.warehouse.adjustment.label'|trans }} + {{ 'marello.inventory.inventorybatch.date_received.label'|trans }} {{ 'marello.inventory.inventorybatch.purchase_price.label'|trans }} {{ 'marello.inventory.inventorybatch.expiration_date.label'|trans }} diff --git a/src/Marello/Bundle/InventoryBundle/Resources/views/Inventory/Datagrid/manageBatches.html.twig b/src/Marello/Bundle/InventoryBundle/Resources/views/Inventory/Datagrid/manageBatches.html.twig new file mode 100644 index 000000000..06e005d81 --- /dev/null +++ b/src/Marello/Bundle/InventoryBundle/Resources/views/Inventory/Datagrid/manageBatches.html.twig @@ -0,0 +1,5 @@ + diff --git a/src/Marello/Bundle/InventoryBundle/Resources/views/InventoryLevel/batchesView.html.twig b/src/Marello/Bundle/InventoryBundle/Resources/views/InventoryLevel/batchesView.html.twig new file mode 100644 index 000000000..541749a3f --- /dev/null +++ b/src/Marello/Bundle/InventoryBundle/Resources/views/InventoryLevel/batchesView.html.twig @@ -0,0 +1,85 @@ +{% extends 'OroUIBundle:actions:view.html.twig' %} +{% import 'OroUIBundle::macros.html.twig' as UI %} +{% import 'OroDataGridBundle::macros.html.twig' as dataGrid %} + +{% block navButtons %} + {{ UI.cancelButton(path('marello_inventory_inventory_view', { 'id': entity.inventoryItem.id }), 'Back'|trans) }} + {% if is_granted('EDIT', entity) %} + {{ UI.editButton({ + 'path' : path('marello_inventory_inventorylevel_manage_batches', { id: entity.id }), + 'entity_label': 'marello.inventory.inventorybatch.entity_label'|trans + }) }} + {% endif %} +{% endblock navButtons %} + +{% block pageHeader %} + {% set breadcrumbs = { + 'entity': form.vars.value, + 'indexPath': path('marello_inventory_inventory_index'), + 'indexLabel': 'marello.inventory.label'|trans, + 'entityTitle': 'marello.inventory.inventorybatch.entity_plural_label'|trans, + 'additional': [{ + 'indexPath': path('marello_inventory_inventory_view', {'id': entity.inventoryItem.id}), + 'indexLabel': entity.inventoryItem.product.sku + }] + } %} + {{ parent() }} +{% endblock pageHeader %} + +{% block content_data %} + {% set id = 'marello-inventory-batches-view' %} + {% set generalSubblocks = [] %} + + {% set productInformationWidget %} +
+
+
+
+ {{ oro_widget_render({ + 'widgetType': 'block', + 'url': path('marello_inventory_widget_info', {id: entity.inventoryItem.id}), + 'title': 'marello.product.product_information'|trans + }) }} +
+
+
+
+ {% endset %} + {% set generalSubblocks = generalSubblocks|merge([{'data' : [productInformationWidget] }]) %} + + {% set inventoryLevelInformationWidget %} +
+
+
+ {{ 'marello.inventory.information.label'|trans }} +
+ {{ UI.renderProperty('marello.inventory.inventorylevel.warehouse.label'|trans, entity.warehouse.label) }} + {{ UI.renderProperty('marello.inventory.inventorylevel.pick_location.label'|trans, entity.picklocation) }} + {{ UI.renderProperty('marello.inventory.inventorylevel.inventory.label'|trans, entity.inventoryQty) }} +
+
+ {% endset %} + {% set generalSubblocks = generalSubblocks|merge([{'data' : [inventoryLevelInformationWidget]}]) %} + + {% set dataBlocks = [ + { + 'title': 'General Information'|trans, + 'class': 'active', + 'subblocks': generalSubblocks + } + ] %} + + {% set dataBlocks = dataBlocks|merge([{ + 'title' : 'marello.inventory.inventorybatch.entity_plural_label'|trans, + 'subblocks': [{ + 'title' : null, + 'data' : [ + dataGrid.renderGrid('marello-inventory-batches', {'inventoryLevelId': entity.id}) + ] + }] + }]) + %} + + {% set data = { 'dataBlocks': dataBlocks } %} + {{ parent() }} +{% endblock content_data %} diff --git a/src/Marello/Bundle/InventoryBundle/Resources/views/InventoryLevel/manageBatches.html.twig b/src/Marello/Bundle/InventoryBundle/Resources/views/InventoryLevel/manageBatches.html.twig index f7afc52be..d61285fe2 100644 --- a/src/Marello/Bundle/InventoryBundle/Resources/views/InventoryLevel/manageBatches.html.twig +++ b/src/Marello/Bundle/InventoryBundle/Resources/views/InventoryLevel/manageBatches.html.twig @@ -9,8 +9,8 @@ {% if entity.id and is_granted('marello_inventory_inventory_update') %} {% set html = '' %} {% set html = UI.saveAndCloseButton({ - 'route': 'marello_inventory_inventory_update', - 'params': {'id': entity.inventoryItem.id} + 'route': 'marello_inventory_inventorylevel_batches_view', + 'params': {'id': entity.id} }) %} {% set html = html ~ UI.saveAndStayButton({ 'route': 'marello_inventory_inventorylevel_manage_batches', @@ -26,10 +26,10 @@ 'entity': form.vars.value, 'indexPath': path('marello_inventory_inventory_index'), 'indexLabel': 'marello.inventory.label'|trans, - 'entityTitle': 'marello.inventory.inventorybatch.entity_plural_label'|trans ~ ' - ' ~ entity.inventoryItem.product.sku, + 'entityTitle': 'marello.inventory.inventorybatch.entity_plural_label'|trans, 'additional': [{ 'indexPath': path('marello_inventory_inventory_update', {'id': entity.inventoryItem.id}), - 'indexLabel': 'marello.inventory.inventorylevel.entity_plural_label'|trans, + 'indexLabel': entity.inventoryItem.product.sku }] } %} {{ parent() }} @@ -55,15 +55,6 @@ {% endset %} {% set generalSubblocks = generalSubblocks|merge([{'data' : [productInformationWidget] }]) %} - {% set totalsWidget %} -
-
- {% placeholder marello_inventory_levels_totals with {'entity' : entity.inventoryItem} %} -
-
- {% endset %} - {% set generalSubblocks = generalSubblocks|merge([{'data' : [totalsWidget] }]) %} - {% set inventoryLevelInformationWidget %}
@@ -72,6 +63,7 @@
{{ UI.renderProperty('marello.inventory.inventorylevel.warehouse.label'|trans, entity.warehouse.label) }} {{ UI.renderProperty('marello.inventory.inventorylevel.pick_location.label'|trans, entity.picklocation) }} + {{ UI.renderProperty('marello.inventory.inventorylevel.inventory.label'|trans, entity.inventoryQty) }}
{% endset %} diff --git a/src/Marello/Bundle/InventoryBundle/Tests/Functional/Controller/InventoryControllerTest.php b/src/Marello/Bundle/InventoryBundle/Tests/Functional/Controller/InventoryControllerTest.php index 7a42ef1d5..7bb70b357 100644 --- a/src/Marello/Bundle/InventoryBundle/Tests/Functional/Controller/InventoryControllerTest.php +++ b/src/Marello/Bundle/InventoryBundle/Tests/Functional/Controller/InventoryControllerTest.php @@ -14,6 +14,10 @@ use Marello\Bundle\InventoryBundle\Tests\Functional\DataFixtures\LoadInventoryData; use Marello\Bundle\PricingBundle\Tests\Functional\DataFixtures\LoadProductChannelPricingData; +/** + * @dbIsolationPerTest + * @nestTransactionsWithSavepoints + */ class InventoryControllerTest extends WebTestCase { /** diff --git a/src/Marello/Bundle/InvoiceBundle/Entity/AbstractInvoice.php b/src/Marello/Bundle/InvoiceBundle/Entity/AbstractInvoice.php index 02883a604..e9b3dfdcc 100644 --- a/src/Marello/Bundle/InvoiceBundle/Entity/AbstractInvoice.php +++ b/src/Marello/Bundle/InvoiceBundle/Entity/AbstractInvoice.php @@ -6,6 +6,7 @@ use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; +use Marello\Bundle\PaymentBundle\Entity\Payment; use Oro\Bundle\AddressBundle\Entity\AbstractAddress; use Oro\Bundle\EntityConfigBundle\Metadata\Annotation as Oro; use Oro\Bundle\OrganizationBundle\Entity\OrganizationAwareInterface; @@ -23,7 +24,7 @@ use Marello\Bundle\SalesBundle\Model\SalesChannelAwareInterface; /** - * @ORM\Entity + * @ORM\Entity(repositoryClass="Marello\Bundle\InvoiceBundle\Entity\Repository\AbstractInvoiceRepository") * @ORM\InheritanceType("SINGLE_TABLE") * @ORM\DiscriminatorColumn(name="type", type="string") * @ORM\DiscriminatorMap({"invoice" = "Invoice", "creditmemo" = "Creditmemo"}) @@ -172,33 +173,6 @@ abstract class AbstractInvoice implements */ protected $paymentMethod; - /** - * @var string - * @ORM\Column(name="payment_reference", type="string", length=255, nullable=true) - * @Oro\ConfigField( - * defaultValues={ - * "dataaudit"={ - * "auditable"=true - * } - * } - * ) - */ - protected $paymentReference; - - /** - * @var string - * - * @ORM\Column(name="payment_details", type="text", nullable=true) - * @Oro\ConfigField( - * defaultValues={ - * "dataaudit"={ - * "auditable"=true - * } - * } - * ) - */ - protected $paymentDetails; - /** * @var string * @@ -302,6 +276,30 @@ abstract class AbstractInvoice implements */ protected $items; + /** + * @var Collection|Payment[] + * + * @ORM\ManyToMany(targetEntity="Marello\Bundle\PaymentBundle\Entity\Payment", cascade={"persist"}) + * @ORM\JoinTable(name="marello_invoice_payments", + * joinColumns={@ORM\JoinColumn(name="invoice_id", referencedColumnName="id", onDelete="CASCADE")}, + * inverseJoinColumns={ + * @ORM\JoinColumn(name="payment_id", referencedColumnName="id", unique=true, onDelete="CASCADE") + * } + * ) + * @ORM\OrderBy({"id" = "ASC"}) + * @Oro\ConfigField( + * defaultValues={ + * "email"={ + * "available_in_template"=true + * }, + * "dataaudit"={ + * "auditable"=true + * } + * } + * ) + */ + protected $payments; + /** * @var int * @@ -372,6 +370,34 @@ abstract class AbstractInvoice implements */ protected $shippingAmountExclTax; + /** + * @var int + * + * @ORM\Column(name="total_due", type="money", nullable=true) + * @Oro\ConfigField( + * defaultValues={ + * "dataaudit"={ + * "auditable"=true + * } + * } + * ) + */ + protected $totalDue = 0; + + /** + * @var int + * + * @ORM\Column(name="total_paid", type="money", nullable=true) + * @Oro\ConfigField( + * defaultValues={ + * "dataaudit"={ + * "auditable"=true + * } + * } + * ) + */ + protected $totalPaid = 0; + /** * @param AbstractAddress|null $billingAddress * @param AbstractAddress|null $shippingAddress @@ -381,6 +407,7 @@ public function __construct( AbstractAddress $shippingAddress = null ) { $this->items = new ArrayCollection(); + $this->payments = new ArrayCollection(); $this->billingAddress = $billingAddress; $this->shippingAddress = $shippingAddress; } @@ -526,44 +553,6 @@ public function setPaymentMethod($paymentMethod) return $this; } - /** - * @return string - */ - public function getPaymentReference() - { - return $this->paymentReference; - } - - /** - * @param string $paymentReference - * @return AbstractInvoice - */ - public function setPaymentReference($paymentReference) - { - $this->paymentReference = $paymentReference; - - return $this; - } - - /** - * @return string - */ - public function getPaymentDetails() - { - return $this->paymentDetails; - } - - /** - * @param string $paymentDetails - * @return AbstractInvoice - */ - public function setPaymentDetails($paymentDetails) - { - $this->paymentDetails = $paymentDetails; - - return $this; - } - /** * @return string */ @@ -734,6 +723,52 @@ public function removeItem(AbstractInvoiceItem $item) return $this; } + /** + * @return Collection|Payment[] + */ + public function getPayments() + { + return $this->payments; + } + + /** + * @param Payment $payment + * + * @return $this + */ + public function addPayment(Payment $payment) + { + if (!$this->payments->contains($payment)) { + $this->payments->add($payment); + $totalPaid = $this->getTotalPaid() ? : 0; + $grandTotal = $this->getGrandTotal() ? : 0; + + $this->setTotalPaid($payment->getTotalPaid() + $totalPaid); + $this->setTotalDue($grandTotal - $this->getTotalPaid()); + } + + return $this; + } + + /** + * @param Payment $payment + * + * @return $this + */ + public function removePayment(Payment $payment) + { + if ($this->payments->contains($payment)) { + $this->payments->removeElement($payment); + $totalPaid = $this->getTotalPaid() ? : 0; + $grandTotal = $this->getGrandTotal() ? : 0; + + $this->setTotalPaid($totalPaid - $payment->getTotalPaid()); + $this->setTotalDue($grandTotal - $this->getTotalPaid()); + } + + return $this; + } + /** * @return int */ @@ -839,6 +874,44 @@ public function setDerivedProperty($id) } } + /** + * @return float + */ + public function getTotalDue() + { + return $this->totalDue; + } + + /** + * @param float $totalDue + * @return $this + */ + public function setTotalDue($totalDue) + { + $this->totalDue = $totalDue; + + return $this; + } + + /** + * @return float + */ + public function getTotalPaid() + { + return $this->totalPaid; + } + + /** + * @param float $totalPaid + * @return $this + */ + public function setTotalPaid($totalPaid) + { + $this->totalPaid = $totalPaid; + + return $this; + } + /** * @return string */ diff --git a/src/Marello/Bundle/InvoiceBundle/Entity/Repository/AbstractInvoiceRepository.php b/src/Marello/Bundle/InvoiceBundle/Entity/Repository/AbstractInvoiceRepository.php new file mode 100644 index 000000000..1e0a25123 --- /dev/null +++ b/src/Marello/Bundle/InvoiceBundle/Entity/Repository/AbstractInvoiceRepository.php @@ -0,0 +1,24 @@ +createQueryBuilder('i'); + $qb + ->where( + $qb->expr()->isMemberOf(':payment', 'i.payments') + ) + ->setParameter('payment', $payment->getId()); + + return $qb->getQuery()->getOneOrNullResult(); + } +} diff --git a/src/Marello/Bundle/InvoiceBundle/Form/Type/InvoiceSelectType.php b/src/Marello/Bundle/InvoiceBundle/Form/Type/InvoiceSelectType.php new file mode 100644 index 000000000..5b8748d2a --- /dev/null +++ b/src/Marello/Bundle/InvoiceBundle/Form/Type/InvoiceSelectType.php @@ -0,0 +1,33 @@ +setDefaults([ + 'class' => AbstractInvoice::class, + 'choice_label' => function (AbstractInvoice $invoice) { + return sprintf('%s: %s', $invoice->getInvoiceType(), $invoice->getInvoiceNumber()); + }, + ]); + } + + public function getParent() + { + return EntityType::class; + } + + public function getBlockPrefix() + { + return self::BLOCK_PREFIX; + } +} diff --git a/src/Marello/Bundle/InvoiceBundle/Migrations/Schema/MarelloInvoiceBundleInstaller.php b/src/Marello/Bundle/InvoiceBundle/Migrations/Schema/MarelloInvoiceBundleInstaller.php index 3791ebb6b..f769f9384 100644 --- a/src/Marello/Bundle/InvoiceBundle/Migrations/Schema/MarelloInvoiceBundleInstaller.php +++ b/src/Marello/Bundle/InvoiceBundle/Migrations/Schema/MarelloInvoiceBundleInstaller.php @@ -29,10 +29,12 @@ public function up(Schema $schema, QueryBag $queries) /** Tables generation **/ $this->createMarelloInvoiceInvoiceTable($schema); $this->createMarelloInvoiceInvoiceItemTable($schema); + $this->createMarelloInvoicePaymentsTable($schema); /** Foreign keys generation **/ $this->addMarelloInvoiceInvoiceForeignKeys($schema); $this->addMarelloInvoiceInvoiceItemForeignKeys($schema); + $this->addMarelloInvoicePaymentsForeignKeys($schema); } /** @@ -51,8 +53,6 @@ protected function createMarelloInvoiceInvoiceTable(Schema $schema) $table->addColumn('invoiced_at', 'datetime', ['notnull' => false]); $table->addColumn('invoice_due_date', 'datetime', ['notnull' => false]); $table->addColumn('payment_method', 'string', ['notnull' => false, 'length' => 255]); - $table->addColumn('payment_reference', 'string', ['notnull' => false, 'length' => 255]); - $table->addColumn('payment_details', 'text', ['notnull' => false]); $table->addColumn('shipping_method', 'string', ['notnull' => false, 'length' => 255]); $table->addColumn('shipping_method_type', 'string', ['notnull' => false, 'length' => 255]); $table->addColumn('order_id', 'integer', ['notnull' => true]); @@ -66,6 +66,8 @@ protected function createMarelloInvoiceInvoiceTable(Schema $schema) $table->addColumn('subtotal', 'money', ['precision' => 19, 'scale' => 4, 'comment' => '(DC2Type:money)']); $table->addColumn('total_tax', 'money', ['precision' => 19, 'scale' => 4, 'comment' => '(DC2Type:money)']); $table->addColumn('grand_total', 'money', ['precision' => 19, 'scale' => 4, 'comment' => '(DC2Type:money)']); + $table->addColumn('total_due', 'money', ['notnull' => false, 'precision' => 19, 'scale' => 4, 'comment' => '(DC2Type:money)']); + $table->addColumn('total_paid', 'money', ['notnull' => false, 'precision' => 19, 'scale' => 4, 'comment' => '(DC2Type:money)']); $table->addColumn( 'shipping_amount_incl_tax', 'money', @@ -139,7 +141,21 @@ protected function createMarelloInvoiceInvoiceItemTable(Schema $schema) $table->setPrimaryKey(['id']); } - + + /** + * Create marello_invoice_invoice_item table + * + * @param Schema $schema + */ + protected function createMarelloInvoicePaymentsTable(Schema $schema) + { + $table = $schema->createTable('marello_invoice_payments'); + $table->addColumn('invoice_id', 'integer', ['notnull' => true]); + $table->addColumn('payment_id', 'integer', ['notnull' => true]); + $table->addUniqueIndex(['payment_id'], null); + $table->setPrimaryKey(['invoice_id', 'payment_id']); + } + /** * Add marello_invoice_invoice foreign keys. * @@ -219,4 +235,24 @@ protected function addMarelloInvoiceInvoiceItemForeignKeys(Schema $schema) ['onDelete' => 'SET NULL', 'onUpdate' => null] ); } + + /** + * @param Schema $schema + */ + protected function addMarelloInvoicePaymentsForeignKeys(Schema $schema) + { + $table = $schema->getTable('marello_invoice_payments'); + $table->addForeignKeyConstraint( + $schema->getTable('marello_invoice_invoice'), + ['invoice_id'], + ['id'], + ['onDelete' => 'CASCADE', 'onUpdate' => null] + ); + $table->addForeignKeyConstraint( + $schema->getTable('marello_payment_payment'), + ['payment_id'], + ['id'], + ['onDelete' => 'CASCADE', 'onUpdate' => null] + ); + } } diff --git a/src/Marello/Bundle/InvoiceBundle/Migrations/Schema/v2_0/MarelloInvoiceBundleAddColumns.php b/src/Marello/Bundle/InvoiceBundle/Migrations/Schema/v2_0/MarelloInvoiceBundleAddColumns.php new file mode 100644 index 000000000..967919d74 --- /dev/null +++ b/src/Marello/Bundle/InvoiceBundle/Migrations/Schema/v2_0/MarelloInvoiceBundleAddColumns.php @@ -0,0 +1,75 @@ +updateInvoiceTable($schema); + if (!$schema->hasTable('marello_invoice_payments')) { + $this->createMarelloInvoicePaymentsTable($schema); + $this->addMarelloInvoicePaymentsForeignKeys($schema); + } + } + + /** + * @param Schema $schema + */ + public function updateInvoiceTable(Schema $schema) + { + $table = $schema->getTable('marello_invoice_invoice'); + $table->addColumn('total_due', 'money', ['notnull' => false, 'precision' => 19, 'scale' => 4, 'comment' => '(DC2Type:money)']); + $table->addColumn('total_paid', 'money', ['notnull' => false, 'precision' => 19, 'scale' => 4, 'comment' => '(DC2Type:money)']); + } + + /** + * Create marello_invoice_invoice_item table + * + * @param Schema $schema + */ + protected function createMarelloInvoicePaymentsTable(Schema $schema) + { + $table = $schema->createTable('marello_invoice_payments'); + $table->addColumn('invoice_id', 'integer', ['notnull' => true]); + $table->addColumn('payment_id', 'integer', ['notnull' => true]); + $table->addUniqueIndex(['payment_id'], null); + $table->setPrimaryKey(['invoice_id', 'payment_id']); + } + + /** + * @param Schema $schema + */ + protected function addMarelloInvoicePaymentsForeignKeys(Schema $schema) + { + $table = $schema->getTable('marello_invoice_payments'); + $table->addForeignKeyConstraint( + $schema->getTable('marello_invoice_invoice'), + ['invoice_id'], + ['id'], + ['onDelete' => 'CASCADE', 'onUpdate' => null] + ); + $table->addForeignKeyConstraint( + $schema->getTable('marello_payment_payment'), + ['payment_id'], + ['id'], + ['onDelete' => 'CASCADE', 'onUpdate' => null] + ); + } +} diff --git a/src/Marello/Bundle/InvoiceBundle/Migrations/Schema/v2_0/MarelloInvoiceBundleAddQuery.php b/src/Marello/Bundle/InvoiceBundle/Migrations/Schema/v2_0/MarelloInvoiceBundleAddQuery.php new file mode 100644 index 000000000..d670dd174 --- /dev/null +++ b/src/Marello/Bundle/InvoiceBundle/Migrations/Schema/v2_0/MarelloInvoiceBundleAddQuery.php @@ -0,0 +1,26 @@ +addQuery(new PaymentsCreationQuery()); + } +} diff --git a/src/Marello/Bundle/InvoiceBundle/Migrations/Schema/v2_0/MarelloInvoiceBundleRemoveColumns.php b/src/Marello/Bundle/InvoiceBundle/Migrations/Schema/v2_0/MarelloInvoiceBundleRemoveColumns.php new file mode 100644 index 000000000..de17a5ed8 --- /dev/null +++ b/src/Marello/Bundle/InvoiceBundle/Migrations/Schema/v2_0/MarelloInvoiceBundleRemoveColumns.php @@ -0,0 +1,37 @@ +updateInvoiceTable($schema); + } + + /** + * @param Schema $schema + */ + public function updateInvoiceTable(Schema $schema) + { + $table = $schema->getTable('marello_invoice_invoice'); + $table->dropColumn('payment_reference'); + $table->dropColumn('payment_details'); + } +} diff --git a/src/Marello/Bundle/InvoiceBundle/Migrations/Schema/v2_0/PaymentsCreationQuery.php b/src/Marello/Bundle/InvoiceBundle/Migrations/Schema/v2_0/PaymentsCreationQuery.php new file mode 100644 index 000000000..b1678a010 --- /dev/null +++ b/src/Marello/Bundle/InvoiceBundle/Migrations/Schema/v2_0/PaymentsCreationQuery.php @@ -0,0 +1,66 @@ +createPayments($logger, true); + + return $logger->getMessages(); + } + + /** + * {@inheritdoc} + */ + public function execute(LoggerInterface $logger) + { + $this->createPayments($logger); + } + + /** + * @param LoggerInterface $logger + * @param bool $dryRun + */ + protected function createPayments(LoggerInterface $logger, $dryRun = false) + { + $invoices = $this->loadInvoices($logger); + foreach ($invoices as $invoice) { + $query = " +INSERT INTO marello_payment_payment +(payment_method, payment_reference, payment_details, total_paid, organization_id, payment_date, created_at) +VALUES +('" . $invoice['payment_method'] . "', '" . $invoice['payment_reference'] . "', '" .$invoice['payment_details'] . "', '" . $invoice['grand_total'] . "', '" . $invoice['organization_id'] . "', '" . $invoice['created_at'] . "', '" . $invoice['created_at'] . "')"; + $this->logQuery($logger, $query); + if (!$dryRun) { + $this->connection->executeQuery($query); + + $paymentId = $this->connection->lastInsertId(); + $query2 = "INSERT INTO marello_invoice_payments (invoice_id, payment_id) VALUES ('" . $invoice['id'] . "', '" . $paymentId . "')"; + $this->connection->executeQuery($query2); + } + } + } + + /** + * @param LoggerInterface $logger + * + * @return array + */ + protected function loadInvoices(LoggerInterface $logger) + { + $sql = 'SELECT id, payment_method, payment_reference, payment_details, grand_total, organization_id, created_at FROM marello_invoice_invoice'; + $this->logQuery($logger, $sql); + + return $this->connection->fetchAll($sql); + } +} diff --git a/src/Marello/Bundle/InvoiceBundle/Pdf/Logo/InvoiceLogoPathProvider.php b/src/Marello/Bundle/InvoiceBundle/Pdf/Logo/InvoiceLogoPathProvider.php index f0008fb5a..7fc99035e 100644 --- a/src/Marello/Bundle/InvoiceBundle/Pdf/Logo/InvoiceLogoPathProvider.php +++ b/src/Marello/Bundle/InvoiceBundle/Pdf/Logo/InvoiceLogoPathProvider.php @@ -58,6 +58,17 @@ public function getInvoiceLogo(SalesChannel $salesChannel, $absolute = false) return $path; } + /** + * @param SalesChannel $salesChannel + * @return mixed + */ + public function getInvoiceLogoWidth(SalesChannel $salesChannel) + { + $key = sprintf('%s.%s', Configuration::CONFIG_NAME, Configuration::CONFIG_KEY_LOGO_WIDTH); + + return $this->configManager->get($key, false, false, $salesChannel); + } + /** * @param SalesChannel $salesChannel * @return mixed @@ -69,6 +80,7 @@ protected function getInvoiceLogoId(SalesChannel $salesChannel) return $this->configManager->get($key, false, false, $salesChannel); } + /** * @param $id * @return object|null diff --git a/src/Marello/Bundle/InvoiceBundle/Pdf/Logo/InvoiceLogoRenderParameterProvider.php b/src/Marello/Bundle/InvoiceBundle/Pdf/Logo/InvoiceLogoRenderParameterProvider.php index a5e30e5fd..592f5736d 100644 --- a/src/Marello/Bundle/InvoiceBundle/Pdf/Logo/InvoiceLogoRenderParameterProvider.php +++ b/src/Marello/Bundle/InvoiceBundle/Pdf/Logo/InvoiceLogoRenderParameterProvider.php @@ -30,6 +30,9 @@ public function getParams($entity, array $options) $salesChannel = $options[self::OPTION_KEY]; } - return ['logo' => $this->logoProvider->getInvoiceLogo($salesChannel, true)]; + return [ + 'logo' => $this->logoProvider->getInvoiceLogo($salesChannel, true), + 'logo_width' => $this->logoProvider->getInvoiceLogoWidth($salesChannel), + ]; } } diff --git a/src/Marello/Bundle/InvoiceBundle/Provider/InvoicePaidAmountProvider.php b/src/Marello/Bundle/InvoiceBundle/Provider/InvoicePaidAmountProvider.php new file mode 100644 index 000000000..9f04cdc34 --- /dev/null +++ b/src/Marello/Bundle/InvoiceBundle/Provider/InvoicePaidAmountProvider.php @@ -0,0 +1,18 @@ +getPayments() as $payment) { + $amount += $payment->getTotalPaid(); + } + + return $amount; + } +} diff --git a/src/Marello/Bundle/InvoiceBundle/Resources/config/oro/actions.yml b/src/Marello/Bundle/InvoiceBundle/Resources/config/oro/actions.yml new file mode 100644 index 000000000..59d941be7 --- /dev/null +++ b/src/Marello/Bundle/InvoiceBundle/Resources/config/oro/actions.yml @@ -0,0 +1,89 @@ +operations: + marello_payment_add: + label: marello.payment.button.add_payment.label + applications: [default] + acl_resource: [EDIT, $.data] + order: 20 + routes: + - marello_invoice_invoice_view + attributes: + invoice_paid_amount: + label: marello.payment.total_paid.label + type: float + payment_method: + label: marello.payment.payment_method.label + type: string + payment_date: + label: marello.payment.payment_date.label + type: object + options: + class: \DateTime + payment_reference: + label: marello.payment.payment_reference.label + type: string + payment_details: + label: marello.payment.payment_details.label + type: string + total_paid: + label: marello.payment.total_paid.label + type: object + options: + class: Oro\Bundle\CurrencyBundle\Entity\Price + action_result: + label: 'result' + type: array + form_options: + attribute_fields: + payment_method: + form_type: Marello\Bundle\PaymentBundle\Form\Type\PaymentMethodSelectType + options: + required: true + constraints: + - NotBlank: ~ + payment_date: + form_type: Oro\Bundle\FormBundle\Form\Type\OroDateTimeType + options: + required: true + constraints: + - NotBlank: ~ + - DateTime: ~ + payment_reference: + form_type: Symfony\Component\Form\Extension\Core\Type\TextType + options: + required: true + constraints: + - NotBlank: ~ + payment_details: + form_type: Symfony\Component\Form\Extension\Core\Type\TextType + options: + required: true + constraints: + - NotBlank: ~ + total_paid: + form_type: Marello\Bundle\OrderBundle\Form\Type\OrderTotalPaidType + options: + required: true + currency: $.data.currency + frontend_options: + options: + width: 2000 + show_dialog: true + template: MarelloPaymentBundle:Action:payment_popup.html.twig + preactions: + - '@call_service_method': + service: marello_invoice.provider.invoice_paid_amount + method: getPaidAmount + method_parameters: [$.data] + attribute: $.invoice_paid_amount + preconditions: + '@and': + - '@less': [$.invoice_paid_amount, $.data.grandTotal] + actions: + - '@call_service_method': + service: marello_payment.action.handler.add_payment + method: handleAction + method_parameters: [$.data, $.payment_method, $.payment_date, $.payment_reference, $.payment_details, $.total_paid.value] + attribute: $.action_result + - '@flash_message': + message: $.action_result.message + type: $.action_result.type diff --git a/src/Marello/Bundle/InvoiceBundle/Resources/config/oro/datagrids.yml b/src/Marello/Bundle/InvoiceBundle/Resources/config/oro/datagrids.yml index a2f3717a0..ef230af46 100644 --- a/src/Marello/Bundle/InvoiceBundle/Resources/config/oro/datagrids.yml +++ b/src/Marello/Bundle/InvoiceBundle/Resources/config/oro/datagrids.yml @@ -38,10 +38,21 @@ datagrids: method: formatCurrency context_resolver: Marello\Bundle\DataGridBundle\Grid\FormatterContextResolver::getResolverCurrencyClosure align: right + totalPaid: + label: marello.invoice.total_paid.label + type: localized_number + method: formatCurrency + context_resolver: Marello\Bundle\DataGridBundle\Grid\FormatterContextResolver::getResolverCurrencyClosure + align: right + totalDue: + label: marello.invoice.total_due.label + type: localized_number + method: formatCurrency + context_resolver: Marello\Bundle\DataGridBundle\Grid\FormatterContextResolver::getResolverCurrencyClosure + align: right invoicedAt: frontend_type: datetime label: marello.invoice.invoiced_at.label - renderable: false createdAt: label: oro.ui.created_at frontend_type: datetime @@ -62,6 +73,10 @@ datagrids: data_name: billingName grandTotal: data_name: i.grandTotal + totalPaid: + data_name: i.totalPaid + totalDue: + data_name: i.totalDue invoicedAt: data_name: i.purchaseDate createdAt: diff --git a/src/Marello/Bundle/InvoiceBundle/Resources/config/services.yml b/src/Marello/Bundle/InvoiceBundle/Resources/config/services.yml index 849ff0d47..410c3f69c 100644 --- a/src/Marello/Bundle/InvoiceBundle/Resources/config/services.yml +++ b/src/Marello/Bundle/InvoiceBundle/Resources/config/services.yml @@ -60,6 +60,10 @@ services: tags: - { name: kernel.event_listener, event: oro_datagrid.datagrid.build.before.marello-invoices-base-grid, method: onBuildBefore } + marello_invoice.provider.invoice_paid_amount: + class: 'Marello\Bundle\InvoiceBundle\Provider\InvoicePaidAmountProvider' + public: true + marello_invoice.provider.invoice_type_choices: class: 'Marello\Bundle\InvoiceBundle\Provider\InvoiceTypeChoicesProvider' public: true @@ -122,4 +126,16 @@ services: arguments: - '@marello_invoice.pdf.provider.table_size' tags: - - { name: marello_pdf.document_table_provider } \ No newline at end of file + - { name: marello_pdf.document_table_provider } + + marello_invoice.form_type.invoice_select: + class: 'Marello\Bundle\InvoiceBundle\Form\Type\InvoiceSelectType' + tags: + - { name: form.type } + + marello_invoice.twig.invoice_extension: + class: 'Marello\Bundle\InvoiceBundle\Twig\InvoiceExtension' + arguments: + - '@doctrine' + tags: + - { name: twig.extension } diff --git a/src/Marello/Bundle/InvoiceBundle/Resources/translations/messages.en.yml b/src/Marello/Bundle/InvoiceBundle/Resources/translations/messages.en.yml index 27b5910a4..5d89cd675 100644 --- a/src/Marello/Bundle/InvoiceBundle/Resources/translations/messages.en.yml +++ b/src/Marello/Bundle/InvoiceBundle/Resources/translations/messages.en.yml @@ -13,9 +13,10 @@ marello: name.label: Ship to Name invoiced_at.label: Invoiced At invoice_due_date.label: Invoice Due Date + payments.label: Payments + total_due.label: Total Due + total_paid.label: Total Paid payment_method.label: Payment Method - payment_reference.label: Payment Reference - payment_details.label: Payment Details payment_term.label: Payment Term shipping_method.label: Shipping Method shipping_method_type.label: Shipping Method Type @@ -52,9 +53,10 @@ marello: name.label: Ship to Name invoiced_at.label: Invoiced At invoice_due_date.label: Invoice Due Date + payments.label: Payments + total_due.label: Total Due + total_paid.label: Total Paid payment_method.label: Payment Method - payment_reference.label: Payment Reference - payment_details.label: Payment Details shipping_method.label: Shipping Method shipping_method_type.label: Shipping Method Type order.label: Order @@ -75,7 +77,7 @@ marello: datablock: general: General - billing_and_payment: Billing & Payment + billing_address: Billing Address delivery: Delivery invoice_items: Invoice Items creditmemo_items: Credit Memo Items @@ -85,6 +87,7 @@ marello: customer_information: Customer Information invoice_totals: Invoice Totals creditmemo_totals: Credit Memo Totals + payments: Payments invoiceitem: id.label: Id @@ -106,10 +109,10 @@ marello: creditmemoitem: id.label: Id - entity_label: Creditmemo Item - entity_plural_label: Creditmemo Items + entity_label: Credit Memo Item + entity_plural_label: Credit Memo Items entity_grid_all_view_label: All %entity_plural_label% - invoice.label: Creditmemo + invoice.label: Invoice quantity.label: Quantity price.label: Price product.label: Product @@ -136,9 +139,10 @@ marello: name.label: Ship to Name invoiced_at.label: Invoiced At invoice_due_date.label: Invoice Due Date + payments.label: Payments + total_due.label: Total Due + total_paid.label: Total Paid payment_method.label: Payment Method - payment_reference.label: Payment Reference - payment_details.label: Payment Details shipping_method.label: Shipping Method shipping_method_type.label: Shipping Method Type order.label: Order diff --git a/src/Marello/Bundle/InvoiceBundle/Resources/translations/pdf.en.yml b/src/Marello/Bundle/InvoiceBundle/Resources/translations/pdf.en.yml index 51491d074..0b1b0fe0f 100644 --- a/src/Marello/Bundle/InvoiceBundle/Resources/translations/pdf.en.yml +++ b/src/Marello/Bundle/InvoiceBundle/Resources/translations/pdf.en.yml @@ -4,6 +4,7 @@ marello: invoice_date.label: "Invoice date" invoice_number.label: "Invoice number" debtor_number.label: "Debtor number" + payment_term.label: "Payment term" subtotal.label: "Subtotal" total.label: "Total" page_number.label: "Page %pageNumber% of %totalPages%" diff --git a/src/Marello/Bundle/InvoiceBundle/Resources/views/Invoice/view.html.twig b/src/Marello/Bundle/InvoiceBundle/Resources/views/Invoice/view.html.twig index 4799e021a..4b5a1a40b 100644 --- a/src/Marello/Bundle/InvoiceBundle/Resources/views/Invoice/view.html.twig +++ b/src/Marello/Bundle/InvoiceBundle/Resources/views/Invoice/view.html.twig @@ -16,9 +16,13 @@ {% endblock pageHeader %} {% block navButtons %} - - {{ 'marello.invoice.pdf.download.label'|trans }} - + {% if is_granted('VIEW', entity) %} + + {% endif %} {% endblock %} {% block content_data %} @@ -57,6 +61,10 @@ {{ UI.renderProperty('marello.invoice.shipping_amount_incl_tax.label'|trans, entity.shippingAmountInclTax|oro_format_currency({'currency':entity.currency})) }} {{ UI.renderProperty('marello.invoice.total_tax.label'|trans, entity.totalTax|oro_format_currency({'currency':entity.currency})) }} {{ UI.renderProperty('marello.invoice.grand_total.label'|trans, entity.grandTotal|oro_format_currency({'currency':entity.currency})) }} + {{ UI.renderProperty('marello.invoice.total_paid.label'|trans, entity.totalPaid|oro_format_currency({'currency':entity.currency})) }} + {{ UI.renderProperty('marello.invoice.total_due.label'|trans, entity.totalDue|oro_format_currency({'currency':entity.currency})) }} +
+
{% endset %} @@ -78,6 +86,9 @@ {% if entity.customer.company.companyNumber %} {{ UI.renderProperty('marello.customer.company.company_number.label'|trans, entity.customer.company.companyNumber) }} {% endif %} + {% if entity.customer.company.taxIdentificationNumber %} + {{ UI.renderProperty('marello.customer.company.tax_identification_number.label'|trans, entity.customer.company.taxIdentificationNumber) }} + {% endif %} {% endif %} {{ UI.renderHtmlProperty( 'marello.customer.entity_label'|trans, @@ -91,28 +102,24 @@ {% endset %} {% set generalSubblocks = generalSubblocks|merge([{'data' : [customerInformation] }]) %} - {% set paymentSubblocks = [] %} + {% set billingSubblocks = [] %} {% set billingAddressBlock %} {{ oro_widget_render({ 'widgetType': 'block', 'url': path('marello_order_order_address', {id: entity.billingAddress.id, typeId: 1}), }) }} {% endset %} - {% set paymentSubblocks = paymentSubblocks|merge([{'data' : [billingAddressBlock] }]) %} + {% set billingSubblocks = billingSubblocks|merge([{'data' : [billingAddressBlock] }]) %} - {% set paymentWidget %} + {% set emptyWidget %}
- {{ UI.renderProperty('marello.invoice.payment_method.label'|trans, entity.paymentMethod) }} - {{ UI.renderProperty('marello.invoice.payment_reference.label'|trans, entity.paymentReference) }} - {{ UI.renderHtmlProperty('marello.invoice.payment_details.label'|trans, entity.paymentDetails|nl2br) }} - {{ UI.renderProperty('marello.invoice.payment_term.label'|trans, (entity.paymentTerm is not empty ? entity.paymentTerm.labels|localized_value : 'N/A')|trans) }}
{% endset %} - {% set paymentSubblocks = paymentSubblocks|merge([{'data' : [paymentWidget] }]) %} + {% set billingSubblocks = billingSubblocks|merge([{'data' : [emptyWidget] }]) %} {% set shippingSubblocks = [] %} {% set shippingAddressBlock %} @@ -146,6 +153,10 @@ {% endset %} + {% set payments %} + {{ dataGrid.renderGrid('marello-invoice-payments-grid', {'invoiceId': entity.id}) }} + {% endset %} + {% set dataBlocks = [ { 'title': 'marello.invoice.datablock.general'|trans, @@ -153,9 +164,9 @@ 'subblocks': generalSubblocks }, { - 'title': 'marello.invoice.datablock.billing_and_payment'|trans, + 'title': 'marello.invoice.datablock.billing_address'|trans, 'class': 'active', - 'subblocks': paymentSubblocks + 'subblocks': billingSubblocks }, { 'title': 'marello.invoice.datablock.delivery'|trans, @@ -168,6 +179,13 @@ 'subblocks': [ { 'data' : [items] } ] + }, + { + 'title': 'marello.invoice.datablock.payments'|trans, + 'class': 'active', + 'subblocks': [ + { 'data' : [payments] } + ] } ] %} diff --git a/src/Marello/Bundle/InvoiceBundle/Resources/views/Pdf/creditmemo.html.twig b/src/Marello/Bundle/InvoiceBundle/Resources/views/Pdf/creditmemo.html.twig index c36265499..0a31984d3 100644 --- a/src/Marello/Bundle/InvoiceBundle/Resources/views/Pdf/creditmemo.html.twig +++ b/src/Marello/Bundle/InvoiceBundle/Resources/views/Pdf/creditmemo.html.twig @@ -249,6 +249,10 @@
{{ 'marello.customer.company.pdf.company_number.label'|trans({}, 'pdf', language) }}:
{{ entity.customer.company.companyNumber }}
{% endif %} + {% if entity.customer.company and entity.customer.company.taxIdentificationNumber %} +
{{ 'marello.customer.company.pdf.tax_identification_number.label'|trans({}, 'pdf', language) }}:
+
{{ entity.customer.company.taxIdentificationNumber }}
+ {% endif %} diff --git a/src/Marello/Bundle/InvoiceBundle/Resources/views/Pdf/invoice.html.twig b/src/Marello/Bundle/InvoiceBundle/Resources/views/Pdf/invoice.html.twig index 915b1f83c..c38722281 100644 --- a/src/Marello/Bundle/InvoiceBundle/Resources/views/Pdf/invoice.html.twig +++ b/src/Marello/Bundle/InvoiceBundle/Resources/views/Pdf/invoice.html.twig @@ -237,7 +237,7 @@ {{ address.postalCode }} {{ address.city }}
{{ ('country.' ~ address.country.iso2code)|trans({}, 'entities', language) }}

- + {% set paymentTerm = marello_get_payment_term_for_customer(entity.customer) %} {# Invoice details #}
@@ -249,6 +249,14 @@
{{ 'marello.customer.company.pdf.company_number.label'|trans({}, 'pdf', language) }}:
{{ entity.customer.company.companyNumber }}
{% endif %} + {% if entity.customer.company and entity.customer.company.taxIdentificationNumber %} +
{{ 'marello.customer.company.pdf.tax_identification_number.label'|trans({}, 'pdf', language) }}:
+
{{ entity.customer.company.taxIdentificationNumber }}
+ {% endif %} + {% if paymentTerm %} +
{{ 'marello.pdf.invoice.payment_term.label'|trans({}, 'pdf', language) }}:
+
{{ 'marello.payment_term.ui.payment_term.term_days'|trans({'%days%': paymentTerm.term }) }}
+ {% endif %}
diff --git a/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/cget_creditmemo_list.yml b/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/cget_creditmemo_list.yml index 4f5457203..36ac54310 100644 --- a/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/cget_creditmemo_list.yml +++ b/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/cget_creditmemo_list.yml @@ -7,8 +7,6 @@ data: invoicedAt: '@marello_creditmemo_0->invoicedAt->format("Y-m-d\TH:i:s\Z")' invoiceDueDate: null paymentMethod: 'Credit Card' - paymentReference: null - paymentDetails: 'American Express refnr. 371449635398431' shippingMethod: null shippingMethodType: null currency: USD @@ -56,8 +54,6 @@ data: invoicedAt: '@marello_creditmemo_1->invoicedAt->format("Y-m-d\TH:i:s\Z")' invoiceDueDate: null paymentMethod: Paypal - paymentReference: null - paymentDetails: null shippingMethod: null shippingMethodType: null currency: GBP diff --git a/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/cget_creditmemo_list_by_order.yml b/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/cget_creditmemo_list_by_order.yml index 148b9ccfd..4f4a3d80d 100644 --- a/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/cget_creditmemo_list_by_order.yml +++ b/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/cget_creditmemo_list_by_order.yml @@ -7,8 +7,6 @@ data: invoicedAt: '@marello_creditmemo_1->invoicedAt->format("Y-m-d\TH:i:s\Z")' invoiceDueDate: null paymentMethod: Paypal - paymentReference: null - paymentDetails: null shippingMethod: null shippingMethodType: null currency: GBP diff --git a/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/cget_invoice_list.yml b/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/cget_invoice_list.yml index 9057e501b..249e13be3 100644 --- a/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/cget_invoice_list.yml +++ b/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/cget_invoice_list.yml @@ -7,8 +7,6 @@ data: invoicedAt: '@marello_invoice_0->invoicedAt->format("Y-m-d\TH:i:s\Z")' invoiceDueDate: null paymentMethod: 'Credit Card' - paymentReference: null - paymentDetails: 'American Express refnr. 371449635398431' shippingMethod: null shippingMethodType: null currency: USD @@ -56,8 +54,6 @@ data: invoicedAt: '@marello_invoice_1->invoicedAt->format("Y-m-d\TH:i:s\Z")' invoiceDueDate: null paymentMethod: Paypal - paymentReference: null - paymentDetails: null shippingMethod: null shippingMethodType: null currency: GBP @@ -114,8 +110,6 @@ data: invoicedAt: '@marello_invoice_2->invoicedAt->format("Y-m-d\TH:i:s\Z")' invoiceDueDate: null paymentMethod: 'Credit Card' - paymentReference: null - paymentDetails: 'American Express refnr. 371449635398431' shippingMethod: null shippingMethodType: null currency: USD @@ -169,8 +163,6 @@ data: invoicedAt: '@marello_invoice_3->invoicedAt->format("Y-m-d\TH:i:s\Z")' invoiceDueDate: null paymentMethod: Paypal - paymentReference: null - paymentDetails: null shippingMethod: null shippingMethodType: null currency: GBP diff --git a/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/cget_invoice_list_by_order.yml b/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/cget_invoice_list_by_order.yml index 82650d8b6..49a6c6df0 100644 --- a/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/cget_invoice_list_by_order.yml +++ b/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/cget_invoice_list_by_order.yml @@ -7,8 +7,6 @@ data: invoicedAt: '@marello_invoice_2->invoicedAt->format("Y-m-d\TH:i:s\Z")' invoiceDueDate: null paymentMethod: 'Credit Card' - paymentReference: null - paymentDetails: 'American Express refnr. 371449635398431' shippingMethod: null shippingMethodType: null currency: USD diff --git a/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/get_creditmemo_by_id.yml b/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/get_creditmemo_by_id.yml index 850783795..ba6c76ba4 100644 --- a/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/get_creditmemo_by_id.yml +++ b/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/get_creditmemo_by_id.yml @@ -6,8 +6,6 @@ data: invoicedAt: '@marello_creditmemo_0->invoicedAt->format("Y-m-d\TH:i:s\Z")' invoiceDueDate: null paymentMethod: 'Credit Card' - paymentReference: null - paymentDetails: 'American Express refnr. 371449635398431' shippingMethod: null shippingMethodType: null currency: USD diff --git a/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/get_creditmemo_by_invoiceNumber.yml b/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/get_creditmemo_by_invoiceNumber.yml index 66e18c5f3..115352ced 100644 --- a/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/get_creditmemo_by_invoiceNumber.yml +++ b/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/get_creditmemo_by_invoiceNumber.yml @@ -6,8 +6,6 @@ data: invoicedAt: '@marello_creditmemo_1->invoicedAt->format("Y-m-d\TH:i:s\Z")' invoiceDueDate: null paymentMethod: Paypal - paymentReference: null - paymentDetails: null shippingMethod: null shippingMethodType: null currency: GBP diff --git a/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/get_invoice_by_id.yml b/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/get_invoice_by_id.yml index 66efd1b98..2fde1b2ee 100644 --- a/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/get_invoice_by_id.yml +++ b/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/get_invoice_by_id.yml @@ -6,8 +6,6 @@ data: invoicedAt: '@marello_invoice_1->invoicedAt->format("Y-m-d\TH:i:s\Z")' invoiceDueDate: null paymentMethod: Paypal - paymentReference: null - paymentDetails: null shippingMethod: null shippingMethodType: null currency: GBP diff --git a/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/get_invoice_by_invoiceNumber.yml b/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/get_invoice_by_invoiceNumber.yml index 66efd1b98..2fde1b2ee 100644 --- a/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/get_invoice_by_invoiceNumber.yml +++ b/src/Marello/Bundle/InvoiceBundle/Tests/Functional/Api/responses/get_invoice_by_invoiceNumber.yml @@ -6,8 +6,6 @@ data: invoicedAt: '@marello_invoice_1->invoicedAt->format("Y-m-d\TH:i:s\Z")' invoiceDueDate: null paymentMethod: Paypal - paymentReference: null - paymentDetails: null shippingMethod: null shippingMethodType: null currency: GBP diff --git a/src/Marello/Bundle/InvoiceBundle/Tests/Unit/Pdf/Logo/InvoiceLogoRenderParameterProviderTest.php b/src/Marello/Bundle/InvoiceBundle/Tests/Unit/Pdf/Logo/InvoiceLogoRenderParameterProviderTest.php index 2f87a0170..7ad7ae5d4 100644 --- a/src/Marello/Bundle/InvoiceBundle/Tests/Unit/Pdf/Logo/InvoiceLogoRenderParameterProviderTest.php +++ b/src/Marello/Bundle/InvoiceBundle/Tests/Unit/Pdf/Logo/InvoiceLogoRenderParameterProviderTest.php @@ -69,7 +69,7 @@ public function testGetParams($entity, $options, $salesChannel, $logoPath) ->willReturn($logoPath) ; - $this->assertEquals(['logo' => $logoPath], $this->provider->getParams($entity, $options)); + $this->assertEquals(['logo' => $logoPath, 'logo_width' => null], $this->provider->getParams($entity, $options)); } public function getParamsProvider() diff --git a/src/Marello/Bundle/InvoiceBundle/Tests/Unit/Pdf/Table/InvoiceTableProviderTest.php b/src/Marello/Bundle/InvoiceBundle/Tests/Unit/Pdf/Table/InvoiceTableProviderTest.php index 952b4f938..20b565b2c 100644 --- a/src/Marello/Bundle/InvoiceBundle/Tests/Unit/Pdf/Table/InvoiceTableProviderTest.php +++ b/src/Marello/Bundle/InvoiceBundle/Tests/Unit/Pdf/Table/InvoiceTableProviderTest.php @@ -126,8 +126,6 @@ public function testGetTables( 'invoicedAt' => new \DateTime('2019-01-01 12:34:56'), 'invoiceDueDate' => new \DateTime('2019-01-02 23:45:01'), 'paymentMethod' => 'payment method', - 'paymentReference' => 'payment reference', - 'paymentDetails' => 'payment details', 'shippingMethod' => 'shipping method', 'shippingMethodType' => 'shipping', 'status' => 'open', diff --git a/src/Marello/Bundle/InvoiceBundle/Twig/InvoiceExtension.php b/src/Marello/Bundle/InvoiceBundle/Twig/InvoiceExtension.php new file mode 100644 index 000000000..80eb03499 --- /dev/null +++ b/src/Marello/Bundle/InvoiceBundle/Twig/InvoiceExtension.php @@ -0,0 +1,65 @@ +doctrine = $doctrine; + } + + /** + * Returns the name of the extension. + * + * @return string The extension name + */ + public function getName() + { + return self::NAME; + } + + /** + * Returns a list of functions to add to the existing list. + * + * @return array An array of functions + */ + public function getFunctions() + { + return [ + new TwigFunction( + 'marello_get_payment_source', + [$this, 'getPaymentSource'] + ) + ]; + } + + /** + * {@inheritdoc} + * @param Payment $payment + * @return AbstractInvoice + */ + public function getPaymentSource(Payment $payment) + { + return $this->doctrine + ->getManagerForClass(AbstractInvoice::class) + ->getRepository(AbstractInvoice::class) + ->findOneByPayment($payment); + } +} diff --git a/src/Marello/Bundle/LayoutBundle/Resources/public/css/scss/main.scss b/src/Marello/Bundle/LayoutBundle/Resources/public/css/scss/main.scss index c807e4367..10b739996 100644 --- a/src/Marello/Bundle/LayoutBundle/Resources/public/css/scss/main.scss +++ b/src/Marello/Bundle/LayoutBundle/Resources/public/css/scss/main.scss @@ -42,7 +42,7 @@ } .marello-line-item-related-field { - margin: 5px 0 0 5px; + margin: 0 0 0 5px; float:left; } diff --git a/src/Marello/Bundle/NotificationBundle/Migrations/Schema/MarelloNotificationBundleInstaller.php b/src/Marello/Bundle/NotificationBundle/Migrations/Schema/MarelloNotificationBundleInstaller.php index 6656c66b8..03897227d 100644 --- a/src/Marello/Bundle/NotificationBundle/Migrations/Schema/MarelloNotificationBundleInstaller.php +++ b/src/Marello/Bundle/NotificationBundle/Migrations/Schema/MarelloNotificationBundleInstaller.php @@ -17,7 +17,7 @@ class MarelloNotificationBundleInstaller implements Installation */ public function getMigrationVersion() { - return 'v1_1'; + return 'v1_2'; } /** @@ -103,7 +103,7 @@ protected function addAttachmentForeignKeys(Schema $schema) ['id'] ); $table->addForeignKeyConstraint( - $schema->getTable('oro_attachment_file'), + $schema->getTable('oro_attachment'), ['attachment_id'], ['id'] ); diff --git a/src/Marello/Bundle/NotificationBundle/Migrations/Schema/v1_2/MarelloNotificationBundle.php b/src/Marello/Bundle/NotificationBundle/Migrations/Schema/v1_2/MarelloNotificationBundle.php new file mode 100644 index 000000000..45bbc31c9 --- /dev/null +++ b/src/Marello/Bundle/NotificationBundle/Migrations/Schema/v1_2/MarelloNotificationBundle.php @@ -0,0 +1,34 @@ +updateAttachmentForeignKeys($schema); + } + + /** + * Add foreign keys. + * + * @param Schema $schema + */ + protected function updateAttachmentForeignKeys(Schema $schema) + { + $table = $schema->getTable('marello_notification_attach'); + $table->removeForeignKey('FK_70347799464E68B'); + $table->addForeignKeyConstraint( + $schema->getTable('oro_attachment'), + ['attachment_id'], + ['id'] + ); + } +} diff --git a/src/Marello/Bundle/OrderBundle/Controller/OrderController.php b/src/Marello/Bundle/OrderBundle/Controller/OrderController.php index 34c0fa5cf..674b18b4e 100644 --- a/src/Marello/Bundle/OrderBundle/Controller/OrderController.php +++ b/src/Marello/Bundle/OrderBundle/Controller/OrderController.php @@ -13,7 +13,6 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\Routing\Annotation\Route; class OrderController extends AbstractController diff --git a/src/Marello/Bundle/OrderBundle/Entity/Order.php b/src/Marello/Bundle/OrderBundle/Entity/Order.php index c30d6e340..e806c952d 100644 --- a/src/Marello/Bundle/OrderBundle/Entity/Order.php +++ b/src/Marello/Bundle/OrderBundle/Entity/Order.php @@ -223,33 +223,6 @@ class Order extends ExtendOrder implements */ protected $paymentMethodOptions; - /** - * @var string - * @ORM\Column(name="payment_reference", type="string", length=255, nullable=true) - * @Oro\ConfigField( - * defaultValues={ - * "dataaudit"={ - * "auditable"=true - * } - * } - * ) - */ - protected $paymentReference; - - /** - * @var string - * - * @ORM\Column(name="payment_details", type="text", nullable=true) - * @Oro\ConfigField( - * defaultValues={ - * "dataaudit"={ - * "auditable"=true - * } - * } - * ) - */ - protected $paymentDetails; - /** * @var double * @@ -925,26 +898,6 @@ public function setPaymentMethodOptions(array $paymentMethodOptions) return $this; } - /** - * @return string - */ - public function getPaymentDetails() - { - return $this->paymentDetails; - } - - /** - * @param string $paymentDetails - * - * @return $this - */ - public function setPaymentDetails($paymentDetails) - { - $this->paymentDetails = $paymentDetails; - - return $this; - } - /** * @return string */ @@ -1041,26 +994,6 @@ public function setInvoicedAt($invoicedAt) return $this; } - /** - * @return string - */ - public function getPaymentReference() - { - return $this->paymentReference; - } - - /** - * @param string $paymentReference - * - * @return $this - */ - public function setPaymentReference($paymentReference) - { - $this->paymentReference = $paymentReference; - - return $this; - } - /** * @param int $id */ diff --git a/src/Marello/Bundle/OrderBundle/EventListener/Doctrine/OrderWorkflowStartListener.php b/src/Marello/Bundle/OrderBundle/EventListener/Doctrine/OrderWorkflowStartListener.php index 079ebaaab..a2edecb6f 100644 --- a/src/Marello/Bundle/OrderBundle/EventListener/Doctrine/OrderWorkflowStartListener.php +++ b/src/Marello/Bundle/OrderBundle/EventListener/Doctrine/OrderWorkflowStartListener.php @@ -97,7 +97,9 @@ protected function getDefaultWorkflowNames(): array { return [ WorkflowNameProviderInterface::ORDER_WORKFLOW_1, - WorkflowNameProviderInterface::ORDER_WORKFLOW_2 + WorkflowNameProviderInterface::ORDER_WORKFLOW_2, + WorkflowNameProviderInterface::ORDER_DEPRECATED_WORKFLOW_1, + WorkflowNameProviderInterface::ORDER_DEPRECATED_WORKFLOW_2 ]; } diff --git a/src/Marello/Bundle/OrderBundle/Form/Type/OrderItemCollectionType.php b/src/Marello/Bundle/OrderBundle/Form/Type/OrderItemCollectionType.php index 707425eb5..82921b3e3 100644 --- a/src/Marello/Bundle/OrderBundle/Form/Type/OrderItemCollectionType.php +++ b/src/Marello/Bundle/OrderBundle/Form/Type/OrderItemCollectionType.php @@ -27,7 +27,7 @@ public function configureOptions(OptionsResolver $resolver) $resolver->setDefaults([ 'entry_type' => OrderItemType::class, 'show_form_when_empty' => false, - 'error_bubbling' => false, + 'error_bubbling' => true, 'constraints' => [new Valid()], 'prototype_name' => '__nameorderitem__', 'prototype' => true, diff --git a/src/Marello/Bundle/OrderBundle/Form/Type/OrderItemType.php b/src/Marello/Bundle/OrderBundle/Form/Type/OrderItemType.php index 38dfcab61..603bb8af5 100644 --- a/src/Marello/Bundle/OrderBundle/Form/Type/OrderItemType.php +++ b/src/Marello/Bundle/OrderBundle/Form/Type/OrderItemType.php @@ -47,39 +47,45 @@ public function buildForm(FormBuilderInterface $builder, array $options) ->add('product', ProductSalesChannelAwareSelectType::class, [ 'required' => true, 'label' => 'marello.product.entity_label', - 'create_enabled' => false, + 'create_enabled' => false ]) ->add('quantity', NumberType::class, [ - 'data' => 1, - ])->add('availableInventory', NumberType::class, [ + 'data' => 1 + ]) + ->add('availableInventory', NumberType::class, [ 'mapped' => false, 'attr' => [ - 'readonly' => true, + 'readonly' => true + ] + ]) + ->add('productUnit', TextType::class, [ + 'attr' => [ + 'readonly' => true ] ]) ->add('price', TextType::class, [ 'attr' => [ - 'readonly' => true, + 'readonly' => true ] ]) ->add('tax', TextType::class, [ 'attr' => [ - 'readonly' => true, + 'readonly' => true ] ]) ->add('taxCode', TextType::class, [ 'attr' => [ - 'readonly' => true, + 'readonly' => true ] ]) ->add('rowTotalExclTax', TextType::class, [ 'attr' => [ - 'readonly' => true, + 'readonly' => true ] ]) ->add('rowTotalInclTax', TextType::class, [ 'attr' => [ - 'readonly' => true, + 'readonly' => true ] ]) ; diff --git a/src/Marello/Bundle/OrderBundle/Form/Type/OrderTotalPaidType.php b/src/Marello/Bundle/OrderBundle/Form/Type/OrderTotalPaidType.php new file mode 100644 index 000000000..ed29022d6 --- /dev/null +++ b/src/Marello/Bundle/OrderBundle/Form/Type/OrderTotalPaidType.php @@ -0,0 +1,93 @@ +localeSettings = $localeSettings; + $this->currencyListProvider = $currencyListProvider; + } + + /** + * @param FormBuilderInterface $builder + * @param array $options + */ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $currencyChoices = []; + if (isset($options['currency']) && $options['currency'] !== null) { + $currencyChoices[$this->localeSettings->getCurrencySymbolByCurrency($options['currency'])] = + $options['currency']; + } else { + foreach ($this->currencyListProvider->getCurrencyList() as $currency) { + $currencyChoices[$this->localeSettings->getCurrencySymbolByCurrency($currency)] = + $currency; + } + } + + $builder + ->add( + 'value', + NumberType::class, + [ + 'grouping' => true, + 'required' => true, + 'constraints' => new NotNull + ] + ) + ->add( + 'currency', + ChoiceType::class, + [ + 'choices' => $currencyChoices + ] + ); + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'data_class' => Price::class, + 'currency' => null + ]); + } + + /** + * {@inheritdoc} + */ + public function getBlockPrefix() + { + return self::BLOCK_PREFIX; + } +} diff --git a/src/Marello/Bundle/OrderBundle/Migrations/Schema/MarelloOrderBundleInstaller.php b/src/Marello/Bundle/OrderBundle/Migrations/Schema/MarelloOrderBundleInstaller.php index 0678baba2..362535355 100644 --- a/src/Marello/Bundle/OrderBundle/Migrations/Schema/MarelloOrderBundleInstaller.php +++ b/src/Marello/Bundle/OrderBundle/Migrations/Schema/MarelloOrderBundleInstaller.php @@ -46,7 +46,7 @@ class MarelloOrderBundleInstaller implements */ public function getMigrationVersion() { - return 'v1_13_2'; + return 'v3_1_2'; } /** @@ -92,8 +92,6 @@ protected function createMarelloOrderOrderTable(Schema $schema) 'notnull' => false, 'comment' => '(DC2Type:json_array)' ] ); - $table->addColumn('payment_reference', 'string', ['notnull' => false, 'length' => 255]); - $table->addColumn('payment_details', 'text', ['notnull' => false]); $table->addColumn('data', 'json_array', ['notnull' => false, 'comment' => '(DC2Type:json_array)']); $table->addColumn( 'shipping_amount_incl_tax', diff --git a/src/Marello/Bundle/OrderBundle/Migrations/Schema/v3_1/MarelloOrderBundle.php b/src/Marello/Bundle/OrderBundle/Migrations/Schema/v3_1/MarelloOrderBundle.php new file mode 100644 index 000000000..18caf1371 --- /dev/null +++ b/src/Marello/Bundle/OrderBundle/Migrations/Schema/v3_1/MarelloOrderBundle.php @@ -0,0 +1,29 @@ +updateOrderTable($schema); + } + + /** + * @param Schema $schema + */ + public function updateOrderTable(Schema $schema) + { + $table = $schema->getTable('marello_order_order'); + $table->dropColumn('payment_reference'); + $table->dropColumn('payment_details'); + } +} diff --git a/src/Marello/Bundle/OrderBundle/Migrations/Schema/v3_1_1/MarelloOrderBundle.php b/src/Marello/Bundle/OrderBundle/Migrations/Schema/v3_1_1/MarelloOrderBundle.php new file mode 100644 index 000000000..92b31b802 --- /dev/null +++ b/src/Marello/Bundle/OrderBundle/Migrations/Schema/v3_1_1/MarelloOrderBundle.php @@ -0,0 +1,73 @@ +updateOrderTable($schema); + $this->updateOrderItemTable($schema); + } + + private function updateOrderTable(Schema $schema) + { + $table = $schema->getTable('marello_order_order'); + if (!$table->hasColumn('delivery_date')) { + $table->addColumn('delivery_date', 'datetime', ['notnull' => false]); + } + if (!$table->hasColumn('order_note')) { + $table->addColumn('order_note', 'text', ['notnull' => false]); + } + if (!$table->hasColumn('po_number')) { + $table->addColumn('po_number', 'string', ['length' => 255, 'notnull' => false]); + } + } + + private function updateOrderItemTable(Schema $schema) + { + $tableName = $this->extendExtension->getNameGenerator()->generateEnumTableName('marello_product_unit'); + // enum table is already available and created... + if ($schema->hasTable($tableName)) { + return; + } + + $table = $schema->getTable('marello_order_order_item'); + $this->extendExtension->addEnumField( + $schema, + $table, + 'productUnit', + 'marello_product_unit', + false, + false, + [ + 'extend' => ['owner' => ExtendScope::OWNER_SYSTEM], + ] + ); + } + + /** + * Sets the ExtendExtension + * + * @param ExtendExtension $extendExtension + */ + public function setExtendExtension(ExtendExtension $extendExtension) + { + $this->extendExtension = $extendExtension; + } +} diff --git a/src/Marello/Bundle/OrderBundle/Migrations/Schema/v1_13_1/MarelloOrderBundle.php b/src/Marello/Bundle/OrderBundle/Migrations/Schema/v3_1_2/MarelloOrderBundle.php similarity index 77% rename from src/Marello/Bundle/OrderBundle/Migrations/Schema/v1_13_1/MarelloOrderBundle.php rename to src/Marello/Bundle/OrderBundle/Migrations/Schema/v3_1_2/MarelloOrderBundle.php index 69560bd4b..d64955a37 100644 --- a/src/Marello/Bundle/OrderBundle/Migrations/Schema/v1_13_1/MarelloOrderBundle.php +++ b/src/Marello/Bundle/OrderBundle/Migrations/Schema/v3_1_2/MarelloOrderBundle.php @@ -1,6 +1,6 @@ getTable('marello_order_order'); - $table->addColumn('locale_id', 'string', ['notnull' => false, 'length' => 255]); - + if (!$table->hasColumn('locale_id')) { + $table->addColumn('locale_id', 'string', ['notnull' => false, 'length' => 255]); + } $queries->addQuery( new UpdateEntityConfigFieldValueQuery( Order::class, diff --git a/src/Marello/Bundle/OrderBundle/Model/WorkflowNameProviderInterface.php b/src/Marello/Bundle/OrderBundle/Model/WorkflowNameProviderInterface.php index e951aef0e..79c2d1389 100644 --- a/src/Marello/Bundle/OrderBundle/Model/WorkflowNameProviderInterface.php +++ b/src/Marello/Bundle/OrderBundle/Model/WorkflowNameProviderInterface.php @@ -4,6 +4,8 @@ interface WorkflowNameProviderInterface { - const ORDER_WORKFLOW_1 = 'marello_order_b2c_workflow_1'; - const ORDER_WORKFLOW_2 = 'marello_order_b2c_workflow_2'; + const ORDER_DEPRECATED_WORKFLOW_1 = 'marello_order_b2c_workflow_1'; + const ORDER_DEPRECATED_WORKFLOW_2 = 'marello_order_b2c_workflow_2'; + const ORDER_WORKFLOW_1 = 'marello_order_b2c_new_workflow_1'; + const ORDER_WORKFLOW_2 = 'marello_order_b2c_new_workflow_2'; } diff --git a/src/Marello/Bundle/OrderBundle/Resources/config/form.yml b/src/Marello/Bundle/OrderBundle/Resources/config/form.yml index 9058b368e..17718fbe8 100644 --- a/src/Marello/Bundle/OrderBundle/Resources/config/form.yml +++ b/src/Marello/Bundle/OrderBundle/Resources/config/form.yml @@ -6,6 +6,14 @@ services: tags: - { name: form.type } + marello_order.form.type.total_paid: + class: Marello\Bundle\OrderBundle\Form\Type\OrderTotalPaidType + arguments: + - '@oro_locale.settings' + - '@oro_currency.config.currency' + tags: + - { name: form.type } + marello_order.form.type.order_update: class: Marello\Bundle\OrderBundle\Form\Type\OrderUpdateType tags: diff --git a/src/Marello/Bundle/OrderBundle/Resources/config/oro/api.yml b/src/Marello/Bundle/OrderBundle/Resources/config/oro/api.yml index 0e33250c1..3e69395ac 100644 --- a/src/Marello/Bundle/OrderBundle/Resources/config/oro/api.yml +++ b/src/Marello/Bundle/OrderBundle/Resources/config/oro/api.yml @@ -60,6 +60,11 @@ api: allow_array: true property_path: order description: 'Filter by order ID' + status_id: + data_type: string + allow_array: true + property_path: status_id + description: 'Filter by status' actions: delete: false delete_list: false diff --git a/src/Marello/Bundle/OrderBundle/Resources/config/oro/datagrids.yml b/src/Marello/Bundle/OrderBundle/Resources/config/oro/datagrids.yml index 677da9169..39c1a5d0c 100644 --- a/src/Marello/Bundle/OrderBundle/Resources/config/oro/datagrids.yml +++ b/src/Marello/Bundle/OrderBundle/Resources/config/oro/datagrids.yml @@ -471,7 +471,7 @@ datagrids: from: - { table: MarelloOrderBundle:OrderItem, alias: oi } join: - left: + inner: - { join: oi.order, alias: o } columns: productSku: diff --git a/src/Marello/Bundle/OrderBundle/Resources/config/oro/workflows.yml b/src/Marello/Bundle/OrderBundle/Resources/config/oro/workflows.yml index ce650eb67..7fe3385f8 100644 --- a/src/Marello/Bundle/OrderBundle/Resources/config/oro/workflows.yml +++ b/src/Marello/Bundle/OrderBundle/Resources/config/oro/workflows.yml @@ -621,3 +621,632 @@ workflows: parameters_mapping: order: $order current_transition: payment_reminder + + marello_order_b2c_new_workflow_1: + entity: Marello\Bundle\OrderBundle\Entity\Order + entity_attribute: order + exclusive_record_groups: [order_b2c] + priority: 5 + defaults: + active: true + + attributes: + payment_reference: + type: string + payment_details: + type: string + total_paid: + type: object + options: + class: Oro\Bundle\CurrencyBundle\Entity\Price + invoiced_at: + type: object + options: + class: \DateTime + note: + type: string + update_balanced_inventory: + type: boolean + steps: + pending: + allowed_transitions: + - invoice + - hold_pending + - cancel + cancelled: + allowed_transitions: [] + pending_on_hold: + allowed_transitions: + - un_hold_pending + invoice_on_hold: + allowed_transitions: + - un_hold_invoice + paid: + allowed_transitions: + - prepare_shipping + invoice: + allowed_transitions: + - hold_invoice + - payment_reminder + - payment_received + pick_and_pack: + allowed_transitions: + - ship + shipped: + allowed_transitions: [] + + transitions: + pending: + step_to: pending + is_start: true + transition_definition: pending_definition + cancel: + step_to: cancelled + transition_definition: cancel_definition + hold_pending: + step_to: pending_on_hold + transition_definition: hold_definition + form_options: + attribute_fields: + note: + form_type: Symfony\Component\Form\Extension\Core\Type\TextareaType + options: + required: false + un_hold_pending: + step_to: pending + transition_definition: un_hold_definition + hold_invoice: + step_to: invoice_on_hold + transition_definition: hold_definition + form_options: + attribute_fields: + note: + form_type: Symfony\Component\Form\Extension\Core\Type\TextareaType + options: + required: false + un_hold_invoice: + step_to: invoice + transition_definition: un_hold_definition + invoice: + step_to: invoice + transition_definition: invoice_definition + form_options: + attribute_fields: + invoiced_at: + form_type: Oro\Bundle\FormBundle\Form\Type\OroDateTimeType + options: + required: true + constraints: + - NotBlank: ~ + - DateTime: ~ + payment_received: + step_to: paid + transition_definition: payment_received_definition + form_options: + attribute_fields: + payment_reference: + form_type: Symfony\Component\Form\Extension\Core\Type\TextType + options: + required: true + constraints: + - NotBlank: ~ + payment_details: + form_type: Symfony\Component\Form\Extension\Core\Type\TextType + options: + required: true + constraints: + - NotBlank: ~ + total_paid: + form_type: Marello\Bundle\OrderBundle\Form\Type\OrderTotalPaidType + options: + required: true + currency: $order.currency + ship: + step_to: shipped + transition_definition: ship_definition + prepare_shipping: + step_to: pick_and_pack + transition_definition: prepare_shipping_definition + payment_reminder: + step_to: invoice + transition_definition: payment_reminder_definition + + transition_definitions: + pending_definition: + actions: + - '@assign_value': + - [$update_balanced_inventory, true] + post_actions: + - '@run_action_group': + action_group: send_order_invoice_email + parameters_mapping: + order: $order + current_transition: pending + - '@run_action_group': + action_group: marello_order_status_change + parameters_mapping: + order: $order + status: 'pending' + cancel_definition: + conditions: + '@and': + - '@sales_channel_has_valid_integration': + salesChannel: $order.salesChannel + actions: + - '@extendable': + events: [extendable_action.order_cancel] + post_actions: + - '@marello_cancel_order': + update_balanced_inventory: $update_balanced_inventory + - '@marello_notification_send': + entity: $order + recipient: $order.customer + template: marello_order_cancelled + - '@run_action_group': + action_group: send_order_invoice_email + parameters_mapping: + order: $order + current_transition: cancel + - '@run_action_group': + action_group: marello_order_status_change + parameters_mapping: + order: $order + status: 'cancelled' + hold_definition: + actions: + - '@tree': + conditions: + '@not_empty': $note + actions: + - '@create_note': + message: $note + target_entity: $order + - '@assign_value': [$note, ~] + post_actions: + - '@run_action_group': + action_group: send_order_invoice_email + parameters_mapping: + order: $order + current_transition: hold + - '@run_action_group': + action_group: marello_order_status_change + parameters_mapping: + order: $order + status: 'hold' + un_hold_definition: + post_actions: + - '@run_action_group': + action_group: send_order_invoice_email + parameters_mapping: + order: $order + current_transition: un_hold + - '@run_action_group': + action_group: marello_order_status_change + parameters_mapping: + order: $order + status: 'processing' + invoice_definition: + conditions: + '@and': + - '@sales_channel_has_valid_integration': + salesChannel: $order.salesChannel + post_actions: + - '@assign_value': + attribute: $order.invoicedAt + value: $invoiced_at + - '@marello_notification_send': + entity: $order + recipient: $order.customer + template: marello_order_invoiced + - '@extendable': + events: [extendable_action.order_invoiced] + - '@run_action_group': + action_group: send_order_invoice_email + parameters_mapping: + order: $order + current_transition: invoice + - '@run_action_group': + action_group: marello_order_status_change + parameters_mapping: + order: $order + status: 'invoiced' + payment_received_definition: + conditions: + '@and': + - '@sales_channel_has_valid_integration': + salesChannel: $order.salesChannel + post_actions: + - '@extendable': + events: [extendable_action.order_paid] + - '@run_action_group': + action_group: send_order_invoice_email + parameters_mapping: + order: $order + current_transition: payment_received + - '@run_action_group': + action_group: marello_order_status_change + parameters_mapping: + order: $order + status: 'paid' + prepare_shipping_definition: + conditions: + '@and': + - '@not_empty': $order.shippingMethod + - '@not_empty': $order.shippingAddress.country + - '@not_empty': $order.shippingAddress.postalCode + - '@not_empty': $order.shippingAddress.city + - '@not_empty': $order.shippingAddress.street + post_actions: + - '@call_service_method': + service: marello_order.factory.shipping_context + method: create + method_parameters: [$order] + attribute: $.result.orderShippingContext + - '@marello_shipment_create': + context: $.result.orderShippingContext + method: $order.shippingMethod + methodType: $order.shippingMethodType + - '@extendable': + events: [extendable_action.create_packingslip] + - '@marello_pick_pack_order': ~ + - '@marello_notification_send': + entity: $order + recipient: $order.customer + template: marello_order_shipping_prepared + - '@run_action_group': + action_group: send_order_invoice_email + parameters_mapping: + order: $order + current_transition: prepare_shipping + - '@run_action_group': + action_group: marello_order_status_change + parameters_mapping: + order: $order + status: 'pick_and_pack' + ship_definition: + conditions: + '@and': + - '@not_empty': $order.shippingAddress.country + - '@not_empty': $order.shippingAddress.postalCode + - '@not_empty': $order.shippingAddress.city + - '@not_empty': $order.shippingAddress.street + - '@sales_channel_has_valid_integration': + salesChannel: $order.salesChannel + post_actions: + - '@extendable': + events: [extendable_action.order_ship] + - '@marello_ship_order': ~ + - '@marello_notification_send': + entity: $order + recipient: $order.customer + template: marello_order_shipped_confirmation + - '@extendable': + events: [extendable_action.order_shipped] + - '@run_action_group': + action_group: send_order_invoice_email + parameters_mapping: + order: $order + current_transition: ship + - '@run_action_group': + action_group: marello_order_status_change + parameters_mapping: + order: $order + status: 'shipped' + payment_reminder_definition: + post_actions: + - '@marello_notification_send': + entity: $order + recipient: $order.customer + template: marello_order_payment_reminder + - '@flash_message': + message: 'Reminder has been sent.' + - '@run_action_group': + action_group: send_order_invoice_email + parameters_mapping: + order: $order + current_transition: payment_reminder + + marello_order_b2c_new_workflow_2: + entity: Marello\Bundle\OrderBundle\Entity\Order + entity_attribute: order + priority: 8 + exclusive_record_groups: [order_b2c] + attributes: + payment_reference: + type: string + payment_details: + type: string + total_paid: + type: object + options: + class: Oro\Bundle\CurrencyBundle\Entity\Price + invoiced_at: + type: object + options: + class: \DateTime + note: + type: string + steps: + pending: + allowed_transitions: + - invoice + invoice: + allowed_transitions: + - prepare_shipping + pick_and_pack: + allowed_transitions: + - ship + shipped: + allowed_transitions: + - payment_received + cancelled: + allowed_transitions: [] + pending_on_hold: + allowed_transitions: + - un_hold_pending + invoice_on_hold: + allowed_transitions: + - un_hold_invoice + paid: + allowed_transitions: [] + transitions: + pending: + step_to: pending + is_start: true + transition_definition: pending_definition + cancel: + step_to: cancelled + transition_definition: cancel_definition + hold_pending: + step_to: pending_on_hold + transition_definition: hold_definition + form_options: + attribute_fields: + note: + form_type: Symfony\Component\Form\Extension\Core\Type\TextAreaType + options: + required: false + un_hold_pending: + step_to: pending + transition_definition: un_hold_definition + hold_invoice: + step_to: invoice_on_hold + transition_definition: hold_definition + form_options: + attribute_fields: + note: + form_type: Symfony\Component\Form\Extension\Core\Type\TextAreaType + options: + required: false + un_hold_invoice: + step_to: invoice + transition_definition: un_hold_definition + invoice: + step_to: invoice + transition_definition: invoice_definition + form_options: + attribute_fields: + invoiced_at: + form_type: Oro\Bundle\FormBundle\Form\Type\OroDateTimeType + options: + required: true + constraints: + - NotBlank: ~ + - DateTime: ~ + payment_received: + step_to: paid + transition_definition: payment_received_definition + form_options: + attribute_fields: + payment_reference: + form_type: Symfony\Component\Form\Extension\Core\Type\TextType + options: + required: true + constraints: + - NotBlank: ~ + payment_details: + form_type: Symfony\Component\Form\Extension\Core\Type\TextType + options: + required: true + constraints: + - NotBlank: ~ + total_paid: + form_type: Marello\Bundle\OrderBundle\Form\Type\OrderTotalPaidType + options: + required: true + currency: $order.currency + ship: + step_to: shipped + transition_definition: ship_definition + prepare_shipping: + step_to: pick_and_pack + transition_definition: prepare_shipping_definition + payment_reminder: + step_to: pending + transition_definition: payment_reminder_definition + + transition_definitions: + pending_definition: + post_actions: + - '@run_action_group': + action_group: send_order_invoice_email + parameters_mapping: + order: $order + current_transition: pending + - '@run_action_group': + action_group: marello_order_status_change + parameters_mapping: + order: $order + status: 'pending' + cancel_definition: + conditions: + '@and': + - '@sales_channel_has_valid_integration': + salesChannel: $order.salesChannel + actions: + - '@extendable': + events: [extendable_action.order_cancel] + post_actions: + - '@marello_cancel_order': ~ + - '@marello_notification_send': + entity: $order + recipient: $order.customer + template: marello_order_cancelled + - '@run_action_group': + action_group: send_order_invoice_email + parameters_mapping: + order: $order + current_transition: cancel + - '@run_action_group': + action_group: marello_order_status_change + parameters_mapping: + order: $order + status: 'cancelled' + hold_definition: + post_actions: + - '@run_action_group': + action_group: send_order_invoice_email + parameters_mapping: + order: $order + current_transition: hold + - '@run_action_group': + action_group: marello_order_status_change + parameters_mapping: + order: $order + status: 'hold' + un_hold_definition: + post_actions: + - '@run_action_group': + action_group: send_order_invoice_email + parameters_mapping: + order: $order + current_transition: un_hold + - '@run_action_group': + action_group: marello_order_status_change + parameters_mapping: + order: $order + status: 'processing' + invoice_definition: + conditions: + '@and': + - '@sales_channel_has_valid_integration': + salesChannel: $order.salesChannel + post_actions: + - '@assign_value': + attribute: $order.invoicedAt + value: $invoiced_at + - '@marello_notification_send': + entity: $order + recipient: $order.customer + template: marello_order_invoiced + - '@extendable': + events: [extendable_action.order_invoiced] + - '@run_action_group': + action_group: send_order_invoice_email + parameters_mapping: + order: $order + current_transition: invoice + - '@run_action_group': + action_group: marello_order_status_change + parameters_mapping: + order: $order + status: 'invoiced' + payment_received_definition: + conditions: + '@and': + - '@sales_channel_has_valid_integration': + salesChannel: $order.salesChannel + post_actions: + - '@marello_notification_send': + entity: $order + recipient: $order.customer + template: marello_order_invoiced + - '@extendable': + events: [extendable_action.order_paid] + - '@run_action_group': + action_group: send_order_invoice_email + parameters_mapping: + order: $order + current_transition: payment_received + - '@run_action_group': + action_group: marello_order_status_change + parameters_mapping: + order: $order + status: 'paid' + prepare_shipping_definition: + conditions: + '@and': + - '@not_empty': $order.shippingMethod + - '@not_empty': $order.shippingAddress.country + - '@not_empty': $order.shippingAddress.postalCode + - '@not_empty': $order.shippingAddress.city + - '@not_empty': $order.shippingAddress.street + post_actions: + - '@call_service_method': + service: marello_order.factory.shipping_context + method: create + method_parameters: [$order] + attribute: $.result.orderShippingContext + - '@marello_shipment_create': + context: $.result.orderShippingContext + method: $order.shippingMethod + methodType: $order.shippingMethodType + - '@extendable': + events: [extendable_action.create_packingslip] + - '@marello_pick_pack_order': ~ + - '@marello_notification_send': + entity: $order + recipient: $order.customer + template: marello_order_shipping_prepared + - '@run_action_group': + action_group: send_order_invoice_email + parameters_mapping: + order: $order + current_transition: prepare_shipping + - '@run_action_group': + action_group: marello_order_status_change + parameters_mapping: + order: $order + status: 'pick_and_pack' + ship_definition: + conditions: + '@and': + - '@not_empty': $order.shippingAddress.country + - '@not_empty': $order.shippingAddress.postalCode + - '@not_empty': $order.shippingAddress.city + - '@not_empty': $order.shippingAddress.street + - '@sales_channel_has_valid_integration': + salesChannel: $order.salesChannel + post_actions: + - '@extendable': + events: [extendable_action.order_ship] + - '@marello_ship_order': ~ + - '@marello_notification_send': + entity: $order + recipient: $order.customer + template: marello_order_shipped_confirmation + - '@extendable': + events: [extendable_action.order_shipped] + - '@run_action_group': + action_group: send_order_invoice_email + parameters_mapping: + order: $order + current_transition: ship + - '@run_action_group': + action_group: marello_order_status_change + parameters_mapping: + order: $order + status: 'shipped' + payment_reminder_definition: + post_actions: + - '@marello_notification_send': + entity: $order + recipient: $order.customer + template: marello_order_payment_reminder + - '@flash_message': + message: 'Reminder has been sent.' + - '@run_action_group': + action_group: send_order_invoice_email + parameters_mapping: + order: $order + current_transition: payment_reminder diff --git a/src/Marello/Bundle/OrderBundle/Resources/doc/api/order.md b/src/Marello/Bundle/OrderBundle/Resources/doc/api/order.md index 70cf8ada3..b536a295c 100644 --- a/src/Marello/Bundle/OrderBundle/Resources/doc/api/order.md +++ b/src/Marello/Bundle/OrderBundle/Resources/doc/api/order.md @@ -44,8 +44,6 @@ Example without address: "grandTotal": "60.5000", "currency": "EUR", "paymentMethod": null, - "paymentReference": null, - "paymentDetails": null, "shippingAmountInclTax": "10.0000", "shippingAmountExclTax": "10.0000", "shippingMethod": null, diff --git a/src/Marello/Bundle/OrderBundle/Resources/public/css/scss/style.scss b/src/Marello/Bundle/OrderBundle/Resources/public/css/scss/style.scss index cd5f123a2..097ad83e5 100644 --- a/src/Marello/Bundle/OrderBundle/Resources/public/css/scss/style.scss +++ b/src/Marello/Bundle/OrderBundle/Resources/public/css/scss/style.scss @@ -29,46 +29,26 @@ width: 315px; } -.order-line-item-quantity { +.order-line-item-tax-code, +.order-line-item-product-unit { width: 243px; input[type="text"] { width:80px; - text-align:right; - float: left; - } -} - -.order-line-item-price { - line-height: 2.3; - width: 243px; - - input[type="text"] { - width:80px; - text-align:right; - padding-left: 17px; - float: left; - } -} - -.order-line-item-tax { - width: 243px; - - input[type="text"] { - width:80px; - text-align:right; - padding-left: 17px; + text-align:left; float: left; } } +.order-line-item-tax, +.order-line-item-price, +.order-line-item-quantity, .order-line-item-total-price { width: 243px; input[type="text"] { width:80px; text-align:right; - padding-left: 17px; float: left; } } diff --git a/src/Marello/Bundle/OrderBundle/Resources/public/js/app/views/order-item-view.js b/src/Marello/Bundle/OrderBundle/Resources/public/js/app/views/order-item-view.js index c4445671e..46e8549eb 100644 --- a/src/Marello/Bundle/OrderBundle/Resources/public/js/app/views/order-item-view.js +++ b/src/Marello/Bundle/OrderBundle/Resources/public/js/app/views/order-item-view.js @@ -92,6 +92,7 @@ define(function(require) { this.fieldsByName.price.val($priceValue); this.fieldsByName.taxCode.val(this.getTaxCode()); + this.fieldsByName.productUnit.val(this.getProductUnit()); this.setRowTotals(); this.setAvailableInventory(); @@ -124,6 +125,13 @@ define(function(require) { return !_.isEmpty(this.data['row_totals'][this.getRowItemIdentifier()]) ? this.data['row_totals'][this.getRowItemIdentifier()] : null; }, + /** + * @returns {Array|Null} + */ + getProductUnit: function() { + return !_.isEmpty(this.data['product_unit']) ? this.data['product_unit'].unit : null; + }, + /** * @returns {Array|Null} */ @@ -152,7 +160,7 @@ define(function(require) { setAvailableInventory: function() { if (this.getProductInventory() === null) { - return + return; } this.fieldsByName.availableInventory.val(this.getProductInventory()); diff --git a/src/Marello/Bundle/OrderBundle/Resources/translations/messages.en.yml b/src/Marello/Bundle/OrderBundle/Resources/translations/messages.en.yml index ec1d8a3fd..52320c3b1 100644 --- a/src/Marello/Bundle/OrderBundle/Resources/translations/messages.en.yml +++ b/src/Marello/Bundle/OrderBundle/Resources/translations/messages.en.yml @@ -59,7 +59,7 @@ marello: edit_action: Edit Address datablock: general: General - billing_and_payment: Billing & Payment + billing_address: Billing Address delivery: Delivery order_items: Order Items activity: Activity @@ -68,6 +68,7 @@ marello: order_totals: Order Totals packing_slips: Packing Slips invoices: Invoices + payments: Payments source_references_information: Source References optional: Optional # OrderItem entity diff --git a/src/Marello/Bundle/OrderBundle/Resources/translations/workflows.en.yml b/src/Marello/Bundle/OrderBundle/Resources/translations/workflows.en.yml index e765e3040..fef518cfa 100644 --- a/src/Marello/Bundle/OrderBundle/Resources/translations/workflows.en.yml +++ b/src/Marello/Bundle/OrderBundle/Resources/translations/workflows.en.yml @@ -1,7 +1,7 @@ oro: workflow: marello_order_b2c_workflow_1: - label: 'Order B2C Workflow #1' + label: 'Order B2C Workflow #1(Deprecated)' attribute: payment_reference: label: 'Payment Reference' @@ -23,7 +23,7 @@ oro: invoice: label: 'Invoiced' paid: - label: 'Order Payed' + label: 'Order Paid' credit: label: 'Closed' pick_and_pack: @@ -57,7 +57,7 @@ oro: label: 'Payment Reminder' marello_order_b2c_workflow_2: - label: 'Order B2C Workflow #2' + label: 'Order B2C Workflow #2(Deprecated)' attribute: payment_reference: label: 'Payment Reference' @@ -79,7 +79,7 @@ oro: invoice: label: 'Complete' paid: - label: 'Order Payed' + label: 'Order Paid' credit: label: 'Closed' pick_and_pack: @@ -115,3 +115,123 @@ oro: label: 'Prepare Shipping' payment_reminder: label: 'Payment Reminder' + + marello_order_b2c_new_workflow_1: + label: 'Order B2C Workflow #1' + attribute: + payment_reference: + label: 'Payment Reference' + payment_details: + label: 'Payment Details' + total_paid: + label: 'Paid Amount' + invoiced_at: + label: 'Invoiced At' + note: + label: 'Note' + step: + pending: + label: 'Pending Order' + cancelled: + label: 'Cancelled' + pending_on_hold: + label: 'On Hold' + invoice_on_hold: + label: 'On Hold' + invoice: + label: 'Invoiced' + paid: + label: 'Order Paid' + credit: + label: 'Closed' + pick_and_pack: + label: 'Pick and Pack' + shipped: + label: 'Complete' + transition: + pending: + label: 'Pending' + cancel: + label: 'Cancel' + hold_pending: + label: 'Hold' + un_hold_pending: + label: 'Un-Hold' + hold_invoice: + label: 'Hold' + un_hold_invoice: + label: 'Un-Hold' + invoice: + label: 'Invoice' + payment_received: + label: 'Payment Received' + ship: + label: 'Ship' + credit: + label: 'Credit' + prepare_shipping: + label: 'Prepare Shipping' + payment_reminder: + label: 'Payment Reminder' + + marello_order_b2c_new_workflow_2: + label: 'Order B2C Workflow #2' + attribute: + payment_reference: + label: 'Payment Reference' + payment_details: + label: 'Payment Details' + total_paid: + label: 'Paid Amount' + invoiced_at: + label: 'Invoiced At' + note: + label: 'Note' + step: + pending: + label: 'Pending Order' + cancelled: + label: 'Cancelled' + pending_on_hold: + label: 'On Hold' + invoice_on_hold: + label: 'On Hold' + invoice: + label: 'Invoiced' + paid: + label: 'Complete' + credit: + label: 'Closed' + pick_and_pack: + label: 'Pick and Pack' + shipped: + label: 'Shipped' + transition: + pending: + label: 'Pending' + cancel: + label: 'Cancel' + hold_pending: + label: 'Hold' + un_hold_pending: + label: 'Un-Hold' + hold_invoice: + label: 'Hold' + un_hold_invoice: + label: 'Un-Hold' + hold_shipped: + label: 'Hold' + un_hold_shipped: + label: 'Un-Hold' + invoice: + label: 'Invoice' + payment_received: + label: 'Payment Received' + ship: + label: 'Ship' + credit: + label: 'Credit' + prepare_shipping: + label: 'Prepare Shipping' + payment_reminder: + label: 'Payment Reminder' \ No newline at end of file diff --git a/src/Marello/Bundle/OrderBundle/Resources/views/Form/fields.html.twig b/src/Marello/Bundle/OrderBundle/Resources/views/Form/fields.html.twig index e25fc6a96..d5907e7a4 100644 --- a/src/Marello/Bundle/OrderBundle/Resources/views/Form/fields.html.twig +++ b/src/Marello/Bundle/OrderBundle/Resources/views/Form/fields.html.twig @@ -17,6 +17,12 @@ {{ form_errors(form.availableInventory) }} + +
+ {{ form_widget(form.productUnit) }} +
+ {{ form_errors(form.productUnit) }} +
{{ form_widget(form.price) }} @@ -29,7 +35,7 @@
{{ form_errors(form.tax) }} - +
{{ form_widget(form.taxCode) }}
@@ -109,6 +115,7 @@ {{ 'marello.product.entity_label'|trans }} {{ 'marello.order.orderitem.quantity.label'|trans }} {{ 'marello.order.orderitem.inventory.label'|trans }} + {{ 'marello.order.orderitem.product_unit.label'|trans }} {{ marello_pricing_vat_aware_label('marello.order.orderitem.price.per_unit.label'|trans) }} {{ 'marello.order.orderitem.tax.label'|trans }} {{ 'marello.order.orderitem.tax_code.label'|trans }} @@ -162,3 +169,15 @@ {{ form_rest(form) }} {% endif %} {% endblock %} + +{% block marello_order_total_paid_widget %} +
+
+ {{ form_widget(form.value) }} + {{ form_widget(form.currency) }} + {{ form_errors(form.value) }} + {{ form_errors(form.currency) }} +
+
+{% endblock %} + diff --git a/src/Marello/Bundle/OrderBundle/Resources/views/Order/view.html.twig b/src/Marello/Bundle/OrderBundle/Resources/views/Order/view.html.twig index 00d4fad59..7a6370dfb 100644 --- a/src/Marello/Bundle/OrderBundle/Resources/views/Order/view.html.twig +++ b/src/Marello/Bundle/OrderBundle/Resources/views/Order/view.html.twig @@ -104,6 +104,8 @@ {{ UI.renderProperty('marello.order.total_tax.label'|trans, entity.totalTax|oro_format_currency({'currency':entity.currency})) }} {{ UI.renderProperty('marello.order.discount_amount.label'|trans, entity.discountAmount|oro_format_currency({'currency':entity.currency})) }} {{ UI.renderProperty('marello.order.grand_total.label'|trans, entity.grandTotal|oro_format_currency({'currency':entity.currency})) }} + {{ UI.renderProperty('marello.invoice.total_paid.label'|trans, marello_get_order_total_paid(entity)|oro_format_currency({'currency':entity.currency})) }} + {{ UI.renderProperty('marello.invoice.total_due.label'|trans, marello_get_order_total_due(entity)|oro_format_currency({'currency':entity.currency})) }} {{ UI.renderProperty('marello.order.coupon_code.label'|trans, entity.couponCode) }} @@ -111,42 +113,24 @@ {% endset %} {% set generalSubblocks = generalSubblocks|merge([{'data' : [totalsWidget] }]) %} - {% set paymentSubblocks = [] %} + {% set billingSubblocks = [] %} {% set billingAddressWidget %} {{ oro_widget_render({ 'widgetType': 'block', 'url': path('marello_order_order_address', {id: entity.billingAddress.id, typeId: 1}), }) }} {% endset %} - {% set paymentSubblocks = paymentSubblocks|merge([{'data' : [billingAddressWidget] }]) %} + {% set billingSubblocks = billingSubblocks|merge([{'data' : [billingAddressWidget] }]) %} - {% set paymentWidget %} + {% set emptyWidget %}
- {{ UI.renderProperty('marello.order.invoiced_at.label'|trans, entity.invoicedAt|oro_format_datetime) }} - {{ UI.renderProperty('marello.order.invoice_reference.label'|trans, entity.invoiceReference) }} -
- -
-
- {% include marello_payment_method_config_template(entity.paymentMethod) with { - 'currency': null, - 'methodData': { - 'identifier': entity.paymentMethod, - 'options': entity.paymentMethodOptions, - } - } %} -
-
-
- {{ UI.renderProperty('marello.order.payment_reference.label'|trans, entity.paymentReference) }} - {{ UI.renderHtmlProperty('marello.order.payment_details.label'|trans, entity.paymentDetails|nl2br) }}
{% endset %} - {% set paymentSubblocks = paymentSubblocks|merge([{'data' : [paymentWidget] }]) %} + {% set billingSubblocks = billingSubblocks|merge([{'data' : [emptyWidget] }]) %} {% set shippingSubblocks = [] %} {% set shippingAddressWidget %} @@ -182,6 +166,10 @@ {{ dataGrid.renderGrid('marello-order-invoices-grid', {'orderId': entity.id}) }} {% endset %} + {% set payments %} + {{ dataGrid.renderGrid('marello-order-payments-grid', {'orderId': entity.id}) }} + {% endset %} + {% set optionalWidget %}
@@ -201,9 +189,9 @@ 'subblocks': generalSubblocks }, { - 'title': 'marello.order.datablock.billing_and_payment'|trans, + 'title': 'marello.order.datablock.billing_address'|trans, 'class': 'active', - 'subblocks': paymentSubblocks + 'subblocks': billingSubblocks }, { 'title': 'marello.order.datablock.delivery'|trans, @@ -221,8 +209,15 @@ 'title': 'marello.order.datablock.invoices'|trans, 'class': 'active', 'subblocks': [ - { 'data' : [invoices] } - ] + { 'data' : [invoices] } + ] + }, + { + 'title': 'marello.order.datablock.payments'|trans, + 'class': 'active', + 'subblocks': [ + { 'data' : [payments] } + ] }, { 'title': 'marello.order.datablock.packing_slips'|trans, diff --git a/src/Marello/Bundle/OrderBundle/Tests/Functional/Api/requests/order_create_with_existing_customer.yml b/src/Marello/Bundle/OrderBundle/Tests/Functional/Api/requests/order_create_with_existing_customer.yml index 66e901df3..c05c9714d 100644 --- a/src/Marello/Bundle/OrderBundle/Tests/Functional/Api/requests/order_create_with_existing_customer.yml +++ b/src/Marello/Bundle/OrderBundle/Tests/Functional/Api/requests/order_create_with_existing_customer.yml @@ -8,8 +8,6 @@ data: grandTotal: 101 currency: 'USD' paymentMethod: 'payment_term_1' - paymentReference: null - paymentDetails: null shippingAmountInclTax: null shippingAmountExclTax: null shippingMethod: 'manual_shipping_1' diff --git a/src/Marello/Bundle/OrderBundle/Tests/Functional/Api/requests/order_create_with_new_customer.yml b/src/Marello/Bundle/OrderBundle/Tests/Functional/Api/requests/order_create_with_new_customer.yml index 9b2b771ad..8f93aa5b7 100644 --- a/src/Marello/Bundle/OrderBundle/Tests/Functional/Api/requests/order_create_with_new_customer.yml +++ b/src/Marello/Bundle/OrderBundle/Tests/Functional/Api/requests/order_create_with_new_customer.yml @@ -19,7 +19,7 @@ data: data: - type: marelloorderitems - id: 'items->first()->id)>' + id: '8da4d8e7-6b25-4c5c-8075-nh3fpu9sca3htc3v' customer: data: type: marellocustomers @@ -35,4 +35,27 @@ included: attributes: firstName: 'test' lastName: 'user' - email: 'new_customer@example.com' \ No newline at end of file + email: 'new_customer@example.com' + - + type: marelloorderitems + id: '8da4d8e7-6b25-4c5c-8075-nh3fpu9sca3htc3v' + attributes: + quantity: 10 + productName: 'name)>' + price: 0 + originalPriceInclTax: 0 + originalPriceExclTax: 0 + purchasePriceIncl: 0 + tax: 0 + taxPercent: 0.21 + rowTotalInclTax: 180.00 + rowTotalExclTax: 180.00 + relationships: + product: + data: + type: marelloproducts + id: 'sku)>' + taxCode: + data: + type: marellotaxcodes + id: 'TAX_HIGH' \ No newline at end of file diff --git a/src/Marello/Bundle/OrderBundle/Tests/Functional/Api/responses/cget_order_list.yml b/src/Marello/Bundle/OrderBundle/Tests/Functional/Api/responses/cget_order_list.yml index 9fb62c1a1..b5404d927 100644 --- a/src/Marello/Bundle/OrderBundle/Tests/Functional/Api/responses/cget_order_list.yml +++ b/src/Marello/Bundle/OrderBundle/Tests/Functional/Api/responses/cget_order_list.yml @@ -11,8 +11,6 @@ data: grandTotal: '280.0000' currency: USD paymentMethod: 'Credit Card' - paymentReference: null - paymentDetails: 'American Express refnr. 371449635398431' shippingAmountInclTax: '0.0000' shippingAmountExclTax: '0.0000' shippingMethod: null @@ -26,10 +24,10 @@ data: salesChannelName: channel2 purchaseDate: '@marello_order_0->purchaseDate->format("Y-m-d\TH:i:s\Z")' data: null - workflowItem: - currentStep: - name: pending - label: 'Pending Order' + #workflowItem: + # currentStep: + # name: pending + # label: 'Pending Order' relationships: items: data: @@ -72,8 +70,6 @@ data: grandTotal: '1511.0000' currency: GBP paymentMethod: Paypal - paymentReference: null - paymentDetails: null shippingAmountInclTax: '10.0000' shippingAmountExclTax: '10.0000' shippingMethod: null @@ -87,10 +83,10 @@ data: salesChannelName: channel3 purchaseDate: '@marello_order_1->purchaseDate->format("Y-m-d\TH:i:s\Z")' data: null - workflowItem: - currentStep: - name: pending - label: 'Pending Order' + #workflowItem: + # currentStep: + # name: pending + # label: 'Pending Order' relationships: items: data: @@ -142,8 +138,6 @@ data: grandTotal: '1110.0000' currency: USD paymentMethod: 'Credit Card' - paymentReference: null - paymentDetails: 'American Express refnr. 371449635398431' shippingAmountInclTax: '0.0000' shippingAmountExclTax: '0.0000' shippingMethod: null @@ -157,10 +151,10 @@ data: salesChannelName: channel2 purchaseDate: '@marello_order_2->purchaseDate->format("Y-m-d\TH:i:s\Z")' data: null - workflowItem: - currentStep: - name: pending - label: 'Pending Order' + #workflowItem: + # currentStep: + # name: pending + # label: 'Pending Order' relationships: items: data: @@ -209,8 +203,6 @@ data: grandTotal: '2030.0000' currency: GBP paymentMethod: Paypal - paymentReference: null - paymentDetails: null shippingAmountInclTax: '0.0000' shippingAmountExclTax: '0.0000' shippingMethod: null @@ -224,10 +216,10 @@ data: salesChannelName: channel3 purchaseDate: '@marello_order_3->purchaseDate->format("Y-m-d\TH:i:s\Z")' data: null - workflowItem: - currentStep: - name: pending - label: 'Pending Order' + #workflowItem: + # currentStep: + # name: pending + # label: 'Pending Order' relationships: items: data: @@ -279,8 +271,6 @@ data: grandTotal: '455.0000' currency: GBP paymentMethod: 'Credit Card' - paymentReference: null - paymentDetails: 'Visa refnr. 4012888888881881' shippingAmountInclTax: '5.0000' shippingAmountExclTax: '5.0000' shippingMethod: null @@ -294,10 +284,10 @@ data: salesChannelName: channel3 purchaseDate: '@marello_order_4->purchaseDate->format("Y-m-d\TH:i:s\Z")' data: null - workflowItem: - currentStep: - name: pending - label: 'Pending Order' + #workflowItem: + # currentStep: + # name: pending + # label: 'Pending Order' relationships: items: data: @@ -340,8 +330,6 @@ data: grandTotal: '920.2500' currency: GBP paymentMethod: Paypal - paymentReference: null - paymentDetails: null shippingAmountInclTax: '0.0000' shippingAmountExclTax: '0.0000' shippingMethod: null @@ -355,10 +343,10 @@ data: salesChannelName: channel3 purchaseDate: '@marello_order_5->purchaseDate->format("Y-m-d\TH:i:s\Z")' data: null - workflowItem: - currentStep: - name: pending - label: 'Pending Order' + #workflowItem: + # currentStep: + # name: pending + # label: 'Pending Order' relationships: items: data: @@ -404,8 +392,6 @@ data: grandTotal: '1595.0000' currency: GBP paymentMethod: Paypal - paymentReference: null - paymentDetails: null shippingAmountInclTax: '5.0000' shippingAmountExclTax: '5.0000' shippingMethod: null @@ -419,10 +405,10 @@ data: salesChannelName: channel3 purchaseDate: '@marello_order_6->purchaseDate->format("Y-m-d\TH:i:s\Z")' data: null - workflowItem: - currentStep: - name: pending - label: 'Pending Order' + #workflowItem: + # currentStep: + # name: pending + # label: 'Pending Order' relationships: items: data: @@ -474,8 +460,6 @@ data: grandTotal: '635.0000' currency: USD paymentMethod: 'Credit Card' - paymentReference: null - paymentDetails: 'Visa refnr. 4012888888881881' shippingAmountInclTax: '5.0000' shippingAmountExclTax: '5.0000' shippingMethod: null @@ -489,10 +473,10 @@ data: salesChannelName: channel2 purchaseDate: '@marello_order_7->purchaseDate->format("Y-m-d\TH:i:s\Z")' data: null - workflowItem: - currentStep: - name: pending - label: 'Pending Order' + #workflowItem: + # currentStep: + # name: pending + # label: 'Pending Order' relationships: items: data: @@ -535,8 +519,6 @@ data: grandTotal: '430.0000' currency: USD paymentMethod: 'Credit Card' - paymentReference: null - paymentDetails: 'Visa refnr. 4012888888881881' shippingAmountInclTax: '5.0000' shippingAmountExclTax: '5.0000' shippingMethod: null @@ -550,10 +532,10 @@ data: salesChannelName: channel2 purchaseDate: '@marello_order_8->purchaseDate->format("Y-m-d\TH:i:s\Z")' data: null - workflowItem: - currentStep: - name: pending - label: 'Pending Order' + #workflowItem: + # currentStep: + # name: pending + # label: 'Pending Order' relationships: items: data: @@ -599,8 +581,6 @@ data: grandTotal: '0.0000' currency: EUR paymentMethod: 'Credit Card' - paymentReference: null - paymentDetails: 'Master Card refnr. 5105105105105100' shippingAmountInclTax: '10.0000' shippingAmountExclTax: '10.0000' shippingMethod: null @@ -614,10 +594,10 @@ data: salesChannelName: channel1 purchaseDate: '@marello_order_9->purchaseDate->format("Y-m-d\TH:i:s\Z")' data: null - workflowItem: - currentStep: - name: pending - label: 'Pending Order' + #workflowItem: + # currentStep: + # name: pending + # label: 'Pending Order' relationships: items: data: diff --git a/src/Marello/Bundle/OrderBundle/Tests/Functional/Api/responses/get_order_by_id.yml b/src/Marello/Bundle/OrderBundle/Tests/Functional/Api/responses/get_order_by_id.yml index 2fa1f090e..58d628478 100644 --- a/src/Marello/Bundle/OrderBundle/Tests/Functional/Api/responses/get_order_by_id.yml +++ b/src/Marello/Bundle/OrderBundle/Tests/Functional/Api/responses/get_order_by_id.yml @@ -10,8 +10,6 @@ data: grandTotal: '1511.0000' currency: GBP paymentMethod: Paypal - paymentReference: null - paymentDetails: null shippingAmountInclTax: '10.0000' shippingAmountExclTax: '10.0000' shippingMethod: null @@ -25,10 +23,10 @@ data: salesChannelName: channel3 purchaseDate: '@marello_order_1->purchaseDate->format("Y-m-d\TH:i:s\Z")' data: null - workflowItem: - currentStep: - name: pending - label: 'Pending Order' + #workflowItem: + # currentStep: + # name: pending + # label: 'Pending Order' relationships: items: data: diff --git a/src/Marello/Bundle/OrderBundle/Tests/Functional/Api/responses/get_order_by_orderNumber.yml b/src/Marello/Bundle/OrderBundle/Tests/Functional/Api/responses/get_order_by_orderNumber.yml index 2fa1f090e..58d628478 100644 --- a/src/Marello/Bundle/OrderBundle/Tests/Functional/Api/responses/get_order_by_orderNumber.yml +++ b/src/Marello/Bundle/OrderBundle/Tests/Functional/Api/responses/get_order_by_orderNumber.yml @@ -10,8 +10,6 @@ data: grandTotal: '1511.0000' currency: GBP paymentMethod: Paypal - paymentReference: null - paymentDetails: null shippingAmountInclTax: '10.0000' shippingAmountExclTax: '10.0000' shippingMethod: null @@ -25,10 +23,10 @@ data: salesChannelName: channel3 purchaseDate: '@marello_order_1->purchaseDate->format("Y-m-d\TH:i:s\Z")' data: null - workflowItem: - currentStep: - name: pending - label: 'Pending Order' + #workflowItem: + # currentStep: + # name: pending + # label: 'Pending Order' relationships: items: data: diff --git a/src/Marello/Bundle/OrderBundle/Tests/Functional/Controller/OrderOnDemandWorkflowTest.php b/src/Marello/Bundle/OrderBundle/Tests/Functional/Controller/OrderOnDemandWorkflowTest.php index c2d6b56c2..ee1b53ed0 100644 --- a/src/Marello/Bundle/OrderBundle/Tests/Functional/Controller/OrderOnDemandWorkflowTest.php +++ b/src/Marello/Bundle/OrderBundle/Tests/Functional/Controller/OrderOnDemandWorkflowTest.php @@ -24,6 +24,9 @@ use Symfony\Component\DomCrawler\Form; use Symfony\Component\HttpFoundation\Response; +/** + * @dbIsolationPerTest + */ class OrderOnDemandWorkflowTest extends WebTestCase { public function setUp() @@ -142,9 +145,19 @@ public function testWorkflow() $this->assertEmpty($beforePackingSlips); $workflowManager = $this->getContainer()->get('oro_workflow.manager'); - $orderWorkflowItem = $workflowManager->getWorkflowItem($order, 'marello_order_b2c_workflow_1'); - $workflowManager->transit($orderWorkflowItem, 'payment_received'); + $orderWorkflowItem = $workflowManager->getWorkflowItem($order, 'marello_order_b2c_new_workflow_1'); + if (!$orderWorkflowItem) { + $orderWorkflowItem = $workflowManager + ->startWorkflow('marello_order_b2c_new_workflow_1', $order, 'pending'); + } $workflowManager->transit($orderWorkflowItem, 'invoice'); + $data = $orderWorkflowItem->getData(); + $data + ->set('payment_reference', 'payment_reference') + ->set('payment_details', 'payment_details') + ->set('total_paid', 100); + $orderWorkflowItem->setData($data); + $workflowManager->transit($orderWorkflowItem, 'payment_received'); $workflowManager->transit($orderWorkflowItem, 'prepare_shipping'); $workflowManager->transit($orderWorkflowItem, 'ship'); diff --git a/src/Marello/Bundle/OrderBundle/Tests/Functional/DataFixtures/LoadOrderData.php b/src/Marello/Bundle/OrderBundle/Tests/Functional/DataFixtures/LoadOrderData.php index ff483b75c..f457039a8 100644 --- a/src/Marello/Bundle/OrderBundle/Tests/Functional/DataFixtures/LoadOrderData.php +++ b/src/Marello/Bundle/OrderBundle/Tests/Functional/DataFixtures/LoadOrderData.php @@ -232,9 +232,6 @@ protected function createOrder($row, Organization $organization) } $orderEntity->setPaymentMethod($row['payment_method']); - if ($row['payment_details'] !== 'NULL') { - $orderEntity->setPaymentDetails($row['payment_details']); - } $orderEntity->setShippingAmountExclTax($row['shipping_amount']); $orderEntity->setShippingAmountInclTax($row['shipping_amount']); @@ -254,7 +251,7 @@ protected function createOrderItem($row, Organization $organization) /** @var Product $product */ $product = $this->manager ->getRepository('MarelloProductBundle:Product') - ->findOneBy(['sku' => $row['sku']]); + ->findOneBy(['sku' => $row['sku'], 'organization' => $organization]); $itemEntity = new OrderItem(); $itemEntity->setProduct($product); diff --git a/src/Marello/Bundle/OrderBundle/Tests/Functional/EventListener/Doctrine/OrderWorkflowStartListenerTest.php b/src/Marello/Bundle/OrderBundle/Tests/Functional/EventListener/Doctrine/OrderWorkflowStartListenerTest.php index be407c0b2..9d982abf9 100644 --- a/src/Marello/Bundle/OrderBundle/Tests/Functional/EventListener/Doctrine/OrderWorkflowStartListenerTest.php +++ b/src/Marello/Bundle/OrderBundle/Tests/Functional/EventListener/Doctrine/OrderWorkflowStartListenerTest.php @@ -53,7 +53,7 @@ public function testOrderHasSingleWorkflowStartedByDefault() $workflowManager = $this->getContainer()->get('oro_workflow.manager'); $workflowItems = $workflowManager->getWorkflowItemsByEntity($order); - self::assertCount(1, $workflowItems); + self::assertCount(0, $workflowItems); } /** @@ -67,10 +67,10 @@ public function testWorkflowStartedIsDefaultWorkflow() $workflowManager = $this->getContainer()->get('oro_workflow.manager'); $workflowItems = $workflowManager->getWorkflowItemsByEntity($order); - self::assertCount(1, $workflowItems); + self::assertCount(0, $workflowItems); /** @var WorkflowItem $workflowItem */ - $workflowItem = array_shift($workflowItems); - self::assertEquals(WorkflowNameProviderInterface::ORDER_WORKFLOW_1, $workflowItem->getWorkflowName()); + //$workflowItem = array_shift($workflowItems); + //self::assertEquals(WorkflowNameProviderInterface::ORDER_WORKFLOW_1, $workflowItem->getWorkflowName()); } /** diff --git a/src/Marello/Bundle/OrderBundle/Tests/Unit/Entity/OrderTest.php b/src/Marello/Bundle/OrderBundle/Tests/Unit/Entity/OrderTest.php index 22227c963..8664df8e3 100644 --- a/src/Marello/Bundle/OrderBundle/Tests/Unit/Entity/OrderTest.php +++ b/src/Marello/Bundle/OrderBundle/Tests/Unit/Entity/OrderTest.php @@ -30,8 +30,6 @@ public function testAccessors() ['grandTotal', 42], ['currency', 'some string'], ['paymentMethod', 'some string'], - ['paymentReference', 'some string'], - ['paymentDetails', 'some string'], ['shippingAmountInclTax', 'some string'], ['shippingAmountExclTax', 'some string'], ['shippingMethod', 3.1415926], diff --git a/src/Marello/Bundle/OrderBundle/Tests/Unit/Twig/OrderExtensionTest.php b/src/Marello/Bundle/OrderBundle/Tests/Unit/Twig/OrderExtensionTest.php index 67d17df54..6b6a719e6 100644 --- a/src/Marello/Bundle/OrderBundle/Tests/Unit/Twig/OrderExtensionTest.php +++ b/src/Marello/Bundle/OrderBundle/Tests/Unit/Twig/OrderExtensionTest.php @@ -64,13 +64,15 @@ public function testNameIsCorrectlySetAndReturnedFromConstant() public function testGetFunctionsAreRegisteredInExtension() { $functions = $this->extension->getFunctions(); - $this->assertCount(4, $functions); + $this->assertCount(6, $functions); $expectedFunctions = array( 'marello_order_can_return', 'marello_order_item_shipped', 'marello_get_order_item_status', - 'marello_get_order_items_for_notification' + 'marello_get_order_items_for_notification', + 'marello_get_order_total_paid', + 'marello_get_order_total_due' ); /** @var \Twig_SimpleFunction $function */ diff --git a/src/Marello/Bundle/OrderBundle/Twig/OrderExtension.php b/src/Marello/Bundle/OrderBundle/Twig/OrderExtension.php index 4f0a2bcce..0022f2150 100644 --- a/src/Marello/Bundle/OrderBundle/Twig/OrderExtension.php +++ b/src/Marello/Bundle/OrderBundle/Twig/OrderExtension.php @@ -3,6 +3,7 @@ namespace Marello\Bundle\OrderBundle\Twig; use Doctrine\Bundle\DoctrineBundle\Registry; +use Marello\Bundle\InvoiceBundle\Entity\AbstractInvoice; use Marello\Bundle\OrderBundle\Entity\Order; use Marello\Bundle\OrderBundle\Entity\OrderItem; use Marello\Bundle\OrderBundle\Migrations\Data\ORM\LoadOrderItemStatusData; @@ -15,12 +16,21 @@ class OrderExtension extends AbstractExtension { const NAME = 'marello_order'; - /** @var Registry $doctrine */ + /** + * @var Registry + */ private $doctrine; - /** @var ShippingPreparedOrderItemsForNotificationProvider $orderItemsForNotificationProvider*/ + /** + * @var ShippingPreparedOrderItemsForNotificationProvider + */ private $orderItemsForNotificationProvider; + /** + * @var array + */ + private $orderInvoices; + /** * Returns the name of the extension. * @@ -54,6 +64,14 @@ public function getFunctions() new TwigFunction( 'marello_get_order_items_for_notification', [$this->orderItemsForNotificationProvider, 'getItems'] + ), + new TwigFunction( + 'marello_get_order_total_paid', + [$this, 'getOrderTotalPaid'] + ), + new TwigFunction( + 'marello_get_order_total_due', + [$this, 'getOrderTotalDue'] ) ]; } @@ -143,4 +161,43 @@ public function setItemsForNotificationProvider( return $this; } + + /** + * @param Order $order + * @return AbstractInvoice[] + */ + private function getOrderInvoices(Order $order) + { + if (!isset($this->orderInvoices[$order->getId()])) { + $this->orderInvoices[$order->getId()] = $this->doctrine + ->getManagerForClass(AbstractInvoice::class) + ->getRepository(AbstractInvoice::class) + ->findBy(['order' => $order]); + } + + return $this->orderInvoices[$order->getId()]; + } + + /** + * @param Order $order + * @return float|int + */ + public function getOrderTotalPaid(Order $order) + { + $orderInvoices = $this->getOrderInvoices($order); + $totalPaid = 0.0; + foreach ($orderInvoices as $invoice) { + $totalPaid += $invoice->getTotalPaid(); + } + + return $totalPaid; + } + /** + * @param Order $order + * @return float|int + */ + public function getOrderTotalDue(Order $order) + { + return ($order->getGrandTotal() - $this->getOrderTotalPaid($order)); + } } diff --git a/src/Marello/Bundle/PackingBundle/Mapper/OrderToPackingSlipMapper.php b/src/Marello/Bundle/PackingBundle/Mapper/OrderToPackingSlipMapper.php index da18b686e..c3c937bd6 100644 --- a/src/Marello/Bundle/PackingBundle/Mapper/OrderToPackingSlipMapper.php +++ b/src/Marello/Bundle/PackingBundle/Mapper/OrderToPackingSlipMapper.php @@ -108,7 +108,7 @@ protected function mapItem(OrderItem $orderItem, Warehouse $warehouse) if ($inventoryBatch->getQuantity() >= $quantity) { $data[$inventoryBatch->getBatchNumber()] = $quantity; break; - } elseif ($batchQty = $inventoryBatch->getQuantity() > 0) { + } elseif (($batchQty = $inventoryBatch->getQuantity()) > 0) { $data[$inventoryBatch->getBatchNumber()] = $batchQty; $quantity = $quantity - $batchQty; } diff --git a/src/Marello/Bundle/PackingBundle/Tests/Unit/Mapper/OrderToPackingSlipMapperTest.php b/src/Marello/Bundle/PackingBundle/Tests/Unit/Mapper/OrderToPackingSlipMapperTest.php index 8e03942fb..25e592a8f 100644 --- a/src/Marello/Bundle/PackingBundle/Tests/Unit/Mapper/OrderToPackingSlipMapperTest.php +++ b/src/Marello/Bundle/PackingBundle/Tests/Unit/Mapper/OrderToPackingSlipMapperTest.php @@ -122,19 +122,19 @@ public function testMap() 'product' => $product1, 'inventoryBatches' => ['000001' => 5], 'quantity' => $orderItem1->getQuantity(), - 'weight' => $product1->getWeight() + 'weight' => ($orderItem1->getQuantity() * $product1->getWeight()) ]), $this->getEntity(PackingSlipItem::class, [ 'orderItem' => $orderItem2, 'product' => $product2, 'quantity' => $orderItem2->getQuantity(), - 'weight' => $product2->getWeight() + 'weight' => ($orderItem2->getQuantity() * $product2->getWeight()) ]), $this->getEntity(PackingSlipItem::class, [ 'orderItem' => $orderItem3, 'product' => $product3, 'quantity' => $orderItem3->getQuantity(), - 'weight' => $product3->getWeight() + 'weight' => ($orderItem3->getQuantity() * $product3->getWeight()) ]), ]; diff --git a/src/Marello/Bundle/PaymentBundle/Action/Handler/AddPaymentActionHandler.php b/src/Marello/Bundle/PaymentBundle/Action/Handler/AddPaymentActionHandler.php new file mode 100644 index 000000000..0eaeb3d16 --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Action/Handler/AddPaymentActionHandler.php @@ -0,0 +1,104 @@ +entityManager = $entityManager; + $this->invoicePaidAmountProvider = $invoicePaidAmountProvider; + } + + /** + * @param AbstractInvoice $entity + * @param string $paymentMethod + * @param \DateTime $paymentDate + * @param string $paymentReference + * @param string $paymentDetails + * @param float $paidTotal + * @return array + */ + public function handleAction( + AbstractInvoice $entity, + $paymentMethod, + \DateTime $paymentDate, + $paymentReference, + $paymentDetails, + $paidTotal + ) { + $paidTotalBefore = $this->invoicePaidAmountProvider->getPaidAmount($entity); + $paidTotalAfter = $paidTotalBefore + $paidTotal; + if ($paidTotalAfter > $entity->getGrandTotal()) { + return [ + 'type' => 'error', + 'message' => 'marello.payment.message.add_payment.error.paid_total_exceed' + ]; + } + $payment = new Payment(); + $payment + ->setPaymentMethod($paymentMethod) + ->setPaymentDate($paymentDate) + ->setPaymentReference($paymentReference) + ->setPaymentDetails($paymentDetails) + ->setTotalPaid($paidTotal) + ->setCurrency($entity->getCurrency()) + ->setStatus($this->findStatusByName(LoadPaymentStatusData::ASSIGNED)) + ->setOrganization($entity->getOrganization()); + $order = $entity->getOrder(); + if ($order && $paymentMethod === $order->getPaymentMethod()) { + $payment->setPaymentMethodOptions($order->getPaymentMethodOptions()); + } + $entity->addPayment($payment); + $this->entityManager->persist($entity); + $this->entityManager->flush(); + + return [ + 'type' => 'success', + 'message' => 'marello.payment.message.add_payment.success' + ]; + } + + /** + * @param string $name + * @return null|object + */ + private function findStatusByName($name) + { + $statusClass = ExtendHelper::buildEnumValueClassName( + LoadPaymentStatusData::PAYMENT_STATUS_ENUM_CLASS + ); + $status = $this->entityManager + ->getRepository($statusClass) + ->find($name); + + if ($status) { + return $status; + } + + return null; + } +} diff --git a/src/Marello/Bundle/PaymentBundle/Controller/PaymentAjaxController.php b/src/Marello/Bundle/PaymentBundle/Controller/PaymentAjaxController.php new file mode 100644 index 000000000..daf0a1f30 --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Controller/PaymentAjaxController.php @@ -0,0 +1,66 @@ +getType($payment); + $submittedData = $request->get($form->getName()); + + $form->submit($submittedData); + + $context = new FormChangeContext( + [ + FormChangeContext::FORM_FIELD => $form, + FormChangeContext::SUBMITTED_DATA_FIELD => $submittedData, + FormChangeContext::RESULT_FIELD => [], + ] + ); + + $formChangesProvider = $this->get('marello_layout.provider.form_changes_data.composite'); + $formChangesProvider + ->setRequiredDataClass(Payment::class) + ->setRequiredFields($request->get('updateFields', [])) + ->processFormChanges($context); + + return new JsonResponse($context->getResult()); + } + + /** + * @param Payment $payment + * @return FormInterface + */ + protected function getType(Payment $payment) + { + return $this->createForm(PaymentCreateType::class, $payment); + } +} diff --git a/src/Marello/Bundle/PaymentBundle/Controller/PaymentController.php b/src/Marello/Bundle/PaymentBundle/Controller/PaymentController.php new file mode 100644 index 000000000..34d4ee58f --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Controller/PaymentController.php @@ -0,0 +1,116 @@ + Payment::class + ]; + } + + /** + * @Route(path="/view/{id}", name="marello_payment_view", requirements={"id"="\d+"}) + * @Template("MarelloPaymentBundle:Payment:view.html.twig") + * @Acl( + * id="marello_payment_view", + * type="entity", + * class="MarelloPaymentBundle:Payment", + * permission="VIEW" + * ) + * + * @param Payment $payment + * + * @return array + */ + public function viewAction(Payment $payment) + { + return [ + 'entity' => $payment, + ]; + } + + /** + * @Route(path="/create", name="marello_payment_create") + * @Template("MarelloPaymentBundle:Payment:create.html.twig") + * @Acl( + * id="marello_payment_create", + * type="entity", + * permission="CREATE", + * class="MarelloPaymentBundle:Payment" + * ) + * @param Request $request + * + * @return array + */ + public function createAction(Request $request) + { + return $this->update($request); + } + + /** + * @Route(path="/update/{id}", name="marello_payment_update", requirements={"id"="\d+"}) + * @Template("MarelloPaymentBundle:Payment:update.html.twig") + * @Acl( + * id="marello_payment_update", + * type="entity", + * permission="EDIT", + * class="MarelloPaymentBundle:Payment" + * ) + * @param Request $request + * @param Payment $entity + * + * @return array + */ + public function updateAction(Request $request, Payment $entity) + { + return $this->update($request, $entity); + } + + /** + * @param Request $request + * @param Payment|null $entity + * @return array|RedirectResponse + */ + protected function update(Request $request, Payment $entity = null) + { + if ($entity === null) { + $entity = new Payment(); + $handler = $this->get('marello_payment.form.handler.payment_create'); + } else { + $handler = $this->get('marello_payment.form.handler.payment_update'); + } + + if ($handler->process($entity)) { + $this->get('session')->getFlashBag()->add( + 'success', + $this->get('translator')->trans('marello.payment_term.ui.payment_term.saved.message') + ); + + return $this->get('oro_ui.router')->redirect($entity); + } + + return [ + 'entity' => $entity, + 'form' => $handler->getFormView(), + ]; + } +} diff --git a/src/Marello/Bundle/PaymentBundle/Controller/PaymentMethodsConfigsRuleController.php b/src/Marello/Bundle/PaymentBundle/Controller/PaymentMethodsConfigsRuleController.php index 8be34b42e..5c4e27580 100644 --- a/src/Marello/Bundle/PaymentBundle/Controller/PaymentMethodsConfigsRuleController.php +++ b/src/Marello/Bundle/PaymentBundle/Controller/PaymentMethodsConfigsRuleController.php @@ -2,18 +2,18 @@ namespace Marello\Bundle\PaymentBundle\Controller; -use Oro\Bundle\DataGridBundle\Extension\MassAction\MassActionDispatcher; use Marello\Bundle\PaymentBundle\Entity\PaymentMethodsConfigsRule; use Marello\Bundle\PaymentBundle\Form\Handler\PaymentMethodsConfigsRuleHandler; use Marello\Bundle\PaymentBundle\Form\Type\PaymentMethodsConfigsRuleType; +use Oro\Bundle\DataGridBundle\Extension\MassAction\MassActionDispatcher; use Oro\Bundle\SecurityBundle\Annotation\Acl; use Oro\Bundle\SecurityBundle\Annotation\AclAncestor; use Oro\Bundle\SecurityBundle\Annotation\CsrfProtection; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Routing\Annotation\Route; /** * Payment Methods Configs Rule Controller @@ -21,7 +21,7 @@ class PaymentMethodsConfigsRuleController extends AbstractController { /** - * @Route("/", name="marello_payment_methods_configs_rule_index") + * @Route(path="/", name="marello_payment_methods_configs_rule_index") * @Template("MarelloPaymentBundle:PaymentMethodsConfigsRule:index.html.twig") * @AclAncestor("marello_payment_methods_configs_rule_view") * @@ -35,7 +35,7 @@ public function indexAction() } /** - * @Route("/create", name="marello_payment_methods_configs_rule_create") + * @Route(path="/create", name="marello_payment_methods_configs_rule_create") * @Template("MarelloPaymentBundle:PaymentMethodsConfigsRule:update.html.twig") * @Acl( * id="marello_payment_methods_configs_rule_create", @@ -53,7 +53,7 @@ public function createAction(Request $request) } /** - * @Route("/view/{id}", name="marello_payment_methods_configs_rule_view", requirements={"id"="\d+"}) + * @Route(path="/view/{id}", name="marello_payment_methods_configs_rule_view", requirements={"id"="\d+"}) * @Template("MarelloPaymentBundle:PaymentMethodsConfigsRule:view.html.twig") * @Acl( * id="marello_payment_methods_configs_rule_view", @@ -74,7 +74,7 @@ public function viewAction(PaymentMethodsConfigsRule $paymentMethodsConfigsRule) } /** - * @Route("/update/{id}", name="marello_payment_methods_configs_rule_update", requirements={"id"="\d+"}) + * @Route(path="/update/{id}", name="marello_payment_methods_configs_rule_update", requirements={"id"="\d+"}) * @Template("MarelloPaymentBundle:PaymentMethodsConfigsRule:update.html.twig") * @Acl( * id="marello_payment_methods_configs_rule_update", @@ -122,7 +122,7 @@ protected function update(PaymentMethodsConfigsRule $entity, Request $request) } /** - * @Route("/{gridName}/massAction/{actionName}", name="marello_payment_methods_configs_massaction") + * @Route(path="/{gridName}/massAction/{actionName}", name="marello_payment_methods_configs_massaction") * @Acl( * id="marello_payment_methods_configs_update", * type="entity", diff --git a/src/Marello/Bundle/PaymentBundle/Entity/Payment.php b/src/Marello/Bundle/PaymentBundle/Entity/Payment.php new file mode 100644 index 000000000..7b78e1b93 --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Entity/Payment.php @@ -0,0 +1,356 @@ +id) { + $this->id = null; + } + } + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * @return AbstractInvoice|null + */ + public function getPaymentSource() + { + return $this->paymentSource; + } + + /** + * @param AbstractInvoice|null $paymentSource + * @return $this + */ + public function setPaymentSource(AbstractInvoice $paymentSource = null) + { + $this->paymentSource = $paymentSource; + + return $this; + } + + /** + * @return int + */ + public function getTotalPaid() + { + return $this->totalPaid; + } + + /** + * @param int $totalPaid + * + * @return $this + */ + public function setTotalPaid($totalPaid) + { + $this->totalPaid = $totalPaid; + + return $this; + } + + /** + * @return string + */ + public function getPaymentMethod() + { + return $this->paymentMethod; + } + + /** + * @param string $paymentMethod + * + * @return $this + */ + public function setPaymentMethod($paymentMethod) + { + $this->paymentMethod = $paymentMethod; + + return $this; + } + + /** + * @return array + */ + public function getPaymentMethodOptions() + { + return $this->paymentMethodOptions; + } + + /** + * @param array $paymentMethodOptions + * @return $this + */ + public function setPaymentMethodOptions(array $paymentMethodOptions) + { + $this->paymentMethodOptions = $paymentMethodOptions; + + return $this; + } + + /** + * @return string + */ + public function getPaymentDetails() + { + return $this->paymentDetails; + } + + /** + * @param string $paymentDetails + * + * @return $this + */ + public function setPaymentDetails($paymentDetails) + { + $this->paymentDetails = $paymentDetails; + + return $this; + } + + /** + * @return string + */ + public function getPaymentReference() + { + return $this->paymentReference; + } + + /** + * @param string $paymentReference + * + * @return $this + */ + public function setPaymentReference($paymentReference) + { + $this->paymentReference = $paymentReference; + + return $this; + } + + /** + * @return \DateTime + */ + public function getPaymentDate() + { + return $this->paymentDate ? : $this->createdAt; + } + + /** + * @param \DateTime|null $paymentDate + * @return $this + */ + public function setPaymentDate(\DateTime $paymentDate = null) + { + $this->paymentDate = $paymentDate; + + return $this; + } + + /** + * @return string + */ + public function getCurrency() + { + return $this->currency; + } + + /** + * @param string $currency + * + * @return $this + */ + public function setCurrency($currency) + { + $this->currency = $currency; + + return $this; + } + + /** + * @return \Extend\Entity\EV_Marello_Payment_Status + */ + public function getStatus() + { + return $this->status; + } + + /** + * @param string $status + * @return $this + */ + public function setStatus($status) + { + $this->status = $status; + + return $this; + } +} diff --git a/src/Marello/Bundle/PaymentBundle/EventListener/PaymentCreationListener.php b/src/Marello/Bundle/PaymentBundle/EventListener/PaymentCreationListener.php new file mode 100644 index 000000000..0e1681945 --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/EventListener/PaymentCreationListener.php @@ -0,0 +1,103 @@ +doctrineHelper = $doctrineHelper; + } + + /** + * @param ExtendableActionEvent $event + */ + public function onOrderPaid(ExtendableActionEvent $event) + { + if (!$this->isCorrectOrderContext($event->getContext())) { + return; + } + $data = $event->getContext()->getData(); + /** @var Order $entity */ + $entity = $data->get('order'); + $entityManager = $this->doctrineHelper->getEntityManagerForClass(Invoice::class); + /** @var Invoice $invoice */ + $invoice = $entityManager + ->getRepository(Invoice::class) + ->findOneBy(['order' => $entity]); + if ($invoice) { + $totalPaid = $data->get('total_paid'); + if ($totalPaid instanceof Price) { + $totalPaid = $totalPaid->getValue(); + } + $payment = new Payment(); + $payment + ->setPaymentMethod($entity->getPaymentMethod()) + ->setPaymentMethodOptions($entity->getPaymentMethodOptions()) + ->setPaymentReference($data->get('payment_reference')) + ->setPaymentDetails($data->get('payment_details')) + ->setTotalPaid($totalPaid) + ->setCurrency($entity->getCurrency() ? : $invoice->getCurrency()) + ->setPaymentDate(new \DateTime('now', new \DateTimeZone('UTC'))) + ->setOrganization($entity->getOrganization()) + ->setStatus($this->findStatusByName(LoadPaymentStatusData::ASSIGNED)); + + $invoice->addPayment($payment); + $entityManager->persist($invoice); + $entityManager->flush(); + } + } + + /** + * @param mixed $context + * @return bool + */ + protected function isCorrectOrderContext($context) + { + return ($context instanceof WorkflowItem + && $context->getData() instanceof WorkflowData + && $context->getData()->has('order') + && $context->getData()->get('order') instanceof Order + ); + } + + /** + * @param string $name + * @return null|object + */ + private function findStatusByName($name) + { + $statusClass = ExtendHelper::buildEnumValueClassName( + LoadPaymentStatusData::PAYMENT_STATUS_ENUM_CLASS + ); + $status = $this->doctrineHelper + ->getEntityManagerForClass($statusClass) + ->getRepository($statusClass) + ->find($name); + + if ($status) { + return $status; + } + + return null; + } +} diff --git a/src/Marello/Bundle/PaymentBundle/Form/Handler/PaymentCreateHandler.php b/src/Marello/Bundle/PaymentBundle/Form/Handler/PaymentCreateHandler.php new file mode 100644 index 000000000..9f7b28d49 --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Form/Handler/PaymentCreateHandler.php @@ -0,0 +1,88 @@ +form = $form; + $this->request = $requestStack->getCurrentRequest(); + $this->manager = $manager; + } + + /** + * @param Payment $entity + * + * @return bool True on successful processing, false otherwise + */ + public function process(Payment $entity) + { + $this->form->setData($entity); + + if (in_array($this->request->getMethod(), ['POST', 'PUT'])) { + $this->submitPostPutRequest($this->form, $this->request); + if ($this->form->isValid()) { + $this->onSuccess($entity); + + return true; + } + } + + return false; + } + + /** + * @param Payment $entity + */ + protected function onSuccess(Payment $entity) + { + $this->manager->persist($entity); + $this->manager->flush(); + $paymentSource = $this->form->get('paymentSource')->getData(); + if ($paymentSource instanceof AbstractInvoice) { + $paymentSource->addPayment($entity); + $this->manager->persist($paymentSource); + $this->manager->flush(); + } + } + + /** + * Returns form instance + * + * @return FormView + */ + public function getFormView() + { + return $this->form->createView(); + } +} diff --git a/src/Marello/Bundle/PaymentBundle/Form/Handler/PaymentUpdateHandler.php b/src/Marello/Bundle/PaymentBundle/Form/Handler/PaymentUpdateHandler.php new file mode 100644 index 000000000..dd4684e75 --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Form/Handler/PaymentUpdateHandler.php @@ -0,0 +1,81 @@ +form = $form; + $this->request = $requestStack->getCurrentRequest(); + $this->manager = $manager; + } + + /** + * @param Payment $entity + * + * @return bool True on successful processing, false otherwise + */ + public function process(Payment $entity) + { + $this->form->setData($entity); + + if (in_array($this->request->getMethod(), ['POST', 'PUT'])) { + $this->submitPostPutRequest($this->form, $this->request); + if ($this->form->isValid()) { + $this->onSuccess($entity); + + return true; + } + } + + return false; + } + + /** + * @param Payment $entity + */ + protected function onSuccess(Payment $entity) + { + $this->manager->persist($entity); + $this->manager->flush(); + } + + /** + * Returns form instance + * + * @return FormView + */ + public function getFormView() + { + return $this->form->createView(); + } +} diff --git a/src/Marello/Bundle/PaymentBundle/Form/Type/PaymentCreateType.php b/src/Marello/Bundle/PaymentBundle/Form/Type/PaymentCreateType.php new file mode 100644 index 000000000..08a91e5f3 --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Form/Type/PaymentCreateType.php @@ -0,0 +1,210 @@ +registry = $registry; + $this->paymentMethodChoicesProvider = $paymentMethodChoicesProvider; + } + + + /** + * {@inheritdoc} + */ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder + ->add( + 'paymentSource', + InvoiceSelectType::class, + [ + 'label' => 'marello.payment.payment_source.label', + 'required' => false, + 'placeholder' => 'Choose Related Entity', + 'empty_data' => null, + 'query_builder' => function (AbstractInvoiceRepository $repository) { + return $repository->createQueryBuilder('invoice') + ->where('invoice.totalPaid < invoice.grandTotal'); + }, + ] + ) + ->add( + 'paymentMethod', + PaymentMethodSelectType::class, + [ + 'label' => 'marello.payment.payment_method.label', + 'required' => true, + 'constraints' => new NotNull, + ] + ) + ->add( + 'paymentDate', + OroDateTimeType::class, + [ + 'label' => 'marello.payment.payment_date.label', + 'required' => true, + ] + ) + ->add( + 'paymentReference', + TextType::class, + [ + 'label' => 'marello.payment.payment_reference.label', + 'required' => false + ] + ) + ->add( + 'paymentDetails', + TextType::class, + [ + 'label' => 'marello.payment.payment_details.label', + 'required' => false + ] + ) + ->add( + 'totalPaid', + OrderTotalPaidType::class, + [ + 'label' => 'marello.payment.total_paid.label', + 'required' => true, + 'mapped' => false + ] + ) + ->add( + 'currency', + HiddenType::class + ); + $builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) { + $form = $event->getForm(); + $paymentSource = $form->get('paymentSource')->getData(); + if ($paymentSource instanceof AbstractInvoice) { + $sourcePaymentMethod = $paymentSource->getPaymentMethod(); + if ($sourcePaymentMethod) { + $allPaymentMethods = $this->paymentMethodChoicesProvider->getMethods(); + $choices = [$allPaymentMethods[$sourcePaymentMethod] => $sourcePaymentMethod]; + $form->remove('paymentMethod'); + $form->add( + 'paymentMethod', + PaymentMethodSelectType::class, + [ + 'label' => 'marello.payment.payment_method.label', + 'required' => true, + 'choices' => $choices, + 'constraints' => new NotNull, + ] + ); + } + if ($paymentSource->getCurrency()) { + $form->remove('totalPaid'); + $form->add( + 'totalPaid', + OrderTotalPaidType::class, + [ + 'label' => 'marello.payment.total_paid.label', + 'required' => true, + 'mapped' => false, + 'currency' => $paymentSource->getCurrency() + ] + ); + } + } + }); + $builder->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) { + $payment = $event->getData(); + if ($payment instanceof Payment) { + $form = $event->getForm(); + $totalPaid = $form->get('totalPaid')->getData(); + if ($totalPaid instanceof Price) { + $payment + ->setTotalPaid($totalPaid->getValue()) + ->setCurrency($totalPaid->getCurrency()); + } + $paymentSource = $form->get('paymentSource')->getData(); + if (!$paymentSource) { + $payment->setStatus($this->getStatus(LoadPaymentStatusData::UNASSIGNED)); + } else { + $payment->setStatus($this->getStatus(LoadPaymentStatusData::ASSIGNED)); + } + } + $event->setData($payment); + }); + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'data_class' => Payment::class, + 'constraints' => [new Valid()] + ]); + } + + /** + * {@inheritdoc} + */ + public function getBlockPrefix() + { + return self::BLOCK_PREFIX; + } + + /** + * @param string $name + * @return null|object + */ + private function getStatus($name) + { + $statusClass = ExtendHelper::buildEnumValueClassName(LoadPaymentStatusData::PAYMENT_STATUS_ENUM_CLASS); + $status = $this->registry + ->getManagerForClass($statusClass) + ->getRepository($statusClass) + ->find($name); + + if ($status) { + return $status; + } + + return null; + } +} diff --git a/src/Marello/Bundle/PaymentBundle/Form/Type/PaymentUpdateType.php b/src/Marello/Bundle/PaymentBundle/Form/Type/PaymentUpdateType.php new file mode 100644 index 000000000..60509ec1e --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Form/Type/PaymentUpdateType.php @@ -0,0 +1,215 @@ +registry = $registry; + } + + /** + * {@inheritdoc} + */ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder + ->add( + 'status', + EnumSelectType::class, + [ + 'label' => 'marello.payment.status.label', + 'enum_code' => 'marello_paymnt_status', + 'configs' => ['allowClear' => false] + ] + ) + ->add( + 'paymentSource', + InvoiceSelectType::class, + [ + 'label' => 'marello.payment.payment_source.label', + 'required' => true, + 'placeholder' => 'Choose Related Entity', + 'empty_data' => null + ] + ) + ->add( + 'paymentReference', + TextType::class, + [ + 'label' => 'marello.payment.payment_reference.label', + 'required' => false + ] + ) + ->add( + 'paymentDetails', + TextType::class, + [ + 'label' => 'marello.payment.payment_details.label', + 'required' => false + ] + ); + $builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) { + /** @var Payment $payment */ + $payment = $event->getData(); + if ($payment) { + $form = $event->getForm(); + if ($payment->getStatus() && $payment->getStatus()->getId() == LoadPaymentStatusData::ASSIGNED) { + $form->remove('status'); + $form->add( + 'status', + EnumSelectType::class, + [ + 'label' => 'marello.payment.status.label', + 'disabled' => true, + 'enum_code' => 'marello_paymnt_status', + 'configs' => ['allowClear' => false] + ] + ); + $form->remove('paymentSource'); + $form->add( + 'paymentSource', + InvoiceSelectType::class, + [ + 'label' => 'marello.payment.payment_source.label', + 'required' => true, + 'mapped' => false, + 'disabled' => true, + 'placeholder' => 'Choose Related Entity', + 'empty_data' => null, + ] + ); + } else { + $currency = $payment->getCurrency(); + $form->remove('paymentSource'); + $form->add( + 'paymentSource', + InvoiceSelectType::class, + [ + 'label' => 'marello.payment.payment_source.label', + 'required' => true, + 'mapped' => false, + 'placeholder' => 'Choose Related Entity', + 'empty_data' => null, + 'query_builder' => function (AbstractInvoiceRepository $repository) use ($currency) { + return $repository->createQueryBuilder('invoice') + ->where('invoice.currency = :currency') + ->andWhere('invoice.totalPaid < invoice.grandTotal') + ->setParameter('currency', $currency); + }, + ] + ); + } + $source = $this->registry + ->getManagerForClass(AbstractInvoice::class) + ->getRepository(AbstractInvoice::class) + ->findOneByPayment($payment); + if ($source) { + $form->get('paymentSource')->setData($source); + } + } + }); + $builder->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) { + /** @var Payment $payment */ + $payment = $event->getData(); + $form = $event->getForm(); + $source = $form->get('paymentSource')->getData(); + if ($source instanceof AbstractInvoice) { + $payment->setPaymentSource($source); + } + if ($source) { + $payment->setStatus($this->getStatus(LoadPaymentStatusData::ASSIGNED)); + } + + $event->setData($payment); + }); + $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) { + /** @var Payment $payment */ + $payment = $event->getData(); + if ($payment) { + $form = $event->getForm(); + $newSource = $form->get('paymentSource')->getData(); + $oldSource = $this->registry + ->getManagerForClass(AbstractInvoice::class) + ->getRepository(AbstractInvoice::class) + ->findOneByPayment($payment); + if ($newSource !== $oldSource) { + $em = $this->registry->getManagerForClass(AbstractInvoice::class); + if ($oldSource) { + $oldSource->removePayment($payment); + $em->persist($oldSource); + $em->flush(); + } + $newSource->addPayment($payment); + $em->persist($newSource); + $em->flush(); + } + } + }); + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'data_class' => Payment::class, + 'constraints' => [new Valid()] + ]); + } + + /** + * {@inheritdoc} + */ + public function getBlockPrefix() + { + return self::BLOCK_PREFIX; + } + + /** + * @param string $name + * @return null|object + */ + private function getStatus($name) + { + $statusClass = ExtendHelper::buildEnumValueClassName(LoadPaymentStatusData::PAYMENT_STATUS_ENUM_CLASS); + $status = $this->registry + ->getManagerForClass($statusClass) + ->getRepository($statusClass) + ->find($name); + + if ($status) { + return $status; + } + + return null; + } +} diff --git a/src/Marello/Bundle/PaymentBundle/Migrations/Data/ORM/LoadPaymentStatusData.php b/src/Marello/Bundle/PaymentBundle/Migrations/Data/ORM/LoadPaymentStatusData.php new file mode 100644 index 000000000..e6000b5d4 --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Migrations/Data/ORM/LoadPaymentStatusData.php @@ -0,0 +1,41 @@ + true, + 'Unassigned' => false, + ]; + + /** + * @param ObjectManager $manager + */ + public function load(ObjectManager $manager) + { + $className = ExtendHelper::buildEnumValueClassName(self::PAYMENT_STATUS_ENUM_CLASS); + + /** @var EnumValueRepository $enumRepo */ + $enumRepo = $manager->getRepository($className); + + $priority = 1; + foreach ($this->data as $name => $isDefault) { + $enumOption = $enumRepo->createEnumValue($name, $priority++, $isDefault); + $manager->persist($enumOption); + } + + $manager->flush(); + } +} diff --git a/src/Marello/Bundle/PaymentBundle/Migrations/Schema/MarelloPaymentBundleInstaller.php b/src/Marello/Bundle/PaymentBundle/Migrations/Schema/MarelloPaymentBundleInstaller.php index b82aee0bd..c5cc4c0a0 100644 --- a/src/Marello/Bundle/PaymentBundle/Migrations/Schema/MarelloPaymentBundleInstaller.php +++ b/src/Marello/Bundle/PaymentBundle/Migrations/Schema/MarelloPaymentBundleInstaller.php @@ -5,25 +5,36 @@ use Doctrine\DBAL\Schema\Schema; use Oro\Bundle\ActivityBundle\Migration\Extension\ActivityExtension; use Oro\Bundle\ActivityBundle\Migration\Extension\ActivityExtensionAwareInterface; +use Oro\Bundle\EntityExtendBundle\EntityConfig\ExtendScope; +use Oro\Bundle\EntityExtendBundle\Migration\Extension\ExtendExtension; +use Oro\Bundle\EntityExtendBundle\Migration\Extension\ExtendExtensionAwareInterface; use Oro\Bundle\MigrationBundle\Migration\Installation; use Oro\Bundle\MigrationBundle\Migration\QueryBag; /** * @SuppressWarnings(PHPMD.TooManyMethods) */ -class MarelloPaymentBundleInstaller implements Installation, ActivityExtensionAwareInterface +class MarelloPaymentBundleInstaller implements + Installation, + ActivityExtensionAwareInterface, + ExtendExtensionAwareInterface { /** * @var ActivityExtension */ protected $activityExtension; + /** + * @var ExtendExtension + */ + protected $extendExtension; + /** * {@inheritdoc} */ public function getMigrationVersion() { - return 'v1_0'; + return 'v2_0'; } /** @@ -31,15 +42,58 @@ public function getMigrationVersion() */ public function up(Schema $schema, QueryBag $queries) { + $this->createMarelloPaymentPaymentTable($schema); $this->createMarelloPaymentMethodConfigTable($schema); $this->createMarelloPaymentMethodsConfigsRuleTable($schema); $this->createMarelloPaymentMethodsConfigsRuleDestinationTable($schema); $this->createMarelloPaymentMethodsConfigsRuleDestinationPostalCodeTable($schema); - $this->addOroPaymentMethodConfigForeignKeys($schema); - $this->addOroPaymentMethodsConfigsRuleForeignKeys($schema); - $this->addOroPaymentMethodsConfigsRuleDestinationForeignKeys($schema); - $this->addOroPaymentMethodsConfigsRuleDestinationPostalCodeForeignKeys($schema); + $this->addMarelloPaymentPaymentForeignKeys($schema); + $this->addMarelloPaymentMethodConfigForeignKeys($schema); + $this->addMarelloPaymentMethodConfigForeignKeys($schema); + $this->addMarelloPaymentMethodsConfigsRuleForeignKeys($schema); + $this->addMarelloPaymentMethodsConfigsRuleDestinationForeignKeys($schema); + $this->addMarelloPaymentMethodsConfigsRuleDestinationPostalCodeForeignKeys($schema); + } + + /** + * Create marello_payment_payment table + * + * @param Schema $schema + */ + protected function createMarelloPaymentPaymentTable(Schema $schema) + { + $table = $schema->createTable('marello_payment_payment'); + $table->addColumn('id', 'integer', ['autoincrement' => true]); + $table->addColumn('organization_id', 'integer', ['notnull' => false]); + $table->addColumn('payment_method', 'string', ['notnull' => false, 'length' => 255]); + $table->addColumn( + 'payment_method_options', + 'json_array', + [ + 'notnull' => false, 'comment' => '(DC2Type:json_array)' + ] + ); + $table->addColumn('payment_reference', 'string', ['notnull' => false, 'length' => 255]); + $table->addColumn('payment_details', 'text', ['notnull' => false]); + $table->addColumn('total_paid', 'money', ['precision' => 19, 'scale' => 4, 'comment' => '(DC2Type:money)']); + $table->addColumn('payment_date', 'datetime', ['notnull' => false, 'comment' => '(DC2Type:datetime)']); + $table->addColumn('currency', 'string', ['notnull' => false, 'length' => 10]); + $table->addColumn('created_at', 'datetime'); + $table->addColumn('updated_at', 'datetime', ['notnull' => false]); + $this->extendExtension->addEnumField( + $schema, + $table, + 'status', + 'marello_paymnt_status', + false, + false, + [ + 'extend' => ['owner' => ExtendScope::OWNER_SYSTEM], + ] + ); + $table->setPrimaryKey(['id']); + $table->addIndex(['organization_id']); } /** @@ -107,13 +161,29 @@ protected function createMarelloPaymentMethodsConfigsRuleDestinationPostalCodeTa $table->addColumn('name', 'text', []); $table->setPrimaryKey(['id']); } - + + /** + * Add marello_payment_payment foreign keys. + * + * @param Schema $schema + */ + protected function addMarelloPaymentPaymentForeignKeys(Schema $schema) + { + $table = $schema->getTable('marello_payment_payment'); + $table->addForeignKeyConstraint( + $schema->getTable('oro_organization'), + ['organization_id'], + ['id'], + ['onDelete' => 'SET NULL', 'onUpdate' => null] + ); + } + /** * Add marello_payment_method_config foreign keys. * * @param Schema $schema */ - protected function addOroPaymentMethodConfigForeignKeys(Schema $schema) + protected function addMarelloPaymentMethodConfigForeignKeys(Schema $schema) { $table = $schema->getTable('marello_payment_method_config'); $table->addForeignKeyConstraint( @@ -129,7 +199,7 @@ protected function addOroPaymentMethodConfigForeignKeys(Schema $schema) * * @param Schema $schema */ - protected function addOroPaymentMethodsConfigsRuleForeignKeys(Schema $schema) + protected function addMarelloPaymentMethodsConfigsRuleForeignKeys(Schema $schema) { $table = $schema->getTable('marello_payment_mtds_cfgs_rl'); $table->addForeignKeyConstraint( @@ -152,7 +222,7 @@ protected function addOroPaymentMethodsConfigsRuleForeignKeys(Schema $schema) * * @param Schema $schema */ - protected function addOroPaymentMethodsConfigsRuleDestinationForeignKeys(Schema $schema) + protected function addMarelloPaymentMethodsConfigsRuleDestinationForeignKeys(Schema $schema) { $table = $schema->getTable('marello_payment_mtds_cfgs_rl_d'); $table->addForeignKeyConstraint( @@ -180,7 +250,7 @@ protected function addOroPaymentMethodsConfigsRuleDestinationForeignKeys(Schema * * @param Schema $schema */ - protected function addOroPaymentMethodsConfigsRuleDestinationPostalCodeForeignKeys(Schema $schema) + protected function addMarelloPaymentMethodsConfigsRuleDestinationPostalCodeForeignKeys(Schema $schema) { $table = $schema->getTable('marello_pmnt_mtdscfgsrl_dst_pc'); $table->addForeignKeyConstraint( @@ -200,4 +270,14 @@ public function setActivityExtension(ActivityExtension $activityExtension) { $this->activityExtension = $activityExtension; } + + /** + * Sets the ExtendExtension + * + * @param ExtendExtension $extendExtension + */ + public function setExtendExtension(ExtendExtension $extendExtension) + { + $this->extendExtension = $extendExtension; + } } diff --git a/src/Marello/Bundle/PaymentBundle/Migrations/Schema/v1_0/MarelloPaymentBundle.php b/src/Marello/Bundle/PaymentBundle/Migrations/Schema/v1_0/MarelloPaymentBundle.php index 4442fe6ad..a1428d450 100644 --- a/src/Marello/Bundle/PaymentBundle/Migrations/Schema/v1_0/MarelloPaymentBundle.php +++ b/src/Marello/Bundle/PaymentBundle/Migrations/Schema/v1_0/MarelloPaymentBundle.php @@ -11,7 +11,7 @@ /** * @SuppressWarnings(PHPMD.TooManyMethods) */ -class MarelloPaymentBundleInstaller implements Migration, ActivityExtensionAwareInterface +class MarelloPaymentBundle implements Migration, ActivityExtensionAwareInterface { /** * @var ActivityExtension @@ -28,10 +28,10 @@ public function up(Schema $schema, QueryBag $queries) $this->createMarelloPaymentMethodsConfigsRuleDestinationTable($schema); $this->createMarelloPaymentMethodsConfigsRuleDestinationPostalCodeTable($schema); - $this->addOroPaymentMethodConfigForeignKeys($schema); - $this->addOroPaymentMethodsConfigsRuleForeignKeys($schema); - $this->addOroPaymentMethodsConfigsRuleDestinationForeignKeys($schema); - $this->addOroPaymentMethodsConfigsRuleDestinationPostalCodeForeignKeys($schema); + $this->addMarelloPaymentMethodConfigForeignKeys($schema); + $this->addMarelloPaymentMethodsConfigsRuleForeignKeys($schema); + $this->addMarelloPaymentMethodsConfigsRuleDestinationForeignKeys($schema); + $this->addMarelloPaymentMethodsConfigsRuleDestinationPostalCodeForeignKeys($schema); } /** @@ -105,7 +105,7 @@ protected function createMarelloPaymentMethodsConfigsRuleDestinationPostalCodeTa * * @param Schema $schema */ - protected function addOroPaymentMethodConfigForeignKeys(Schema $schema) + protected function addMarelloPaymentMethodConfigForeignKeys(Schema $schema) { $table = $schema->getTable('marello_payment_method_config'); $table->addForeignKeyConstraint( @@ -121,7 +121,7 @@ protected function addOroPaymentMethodConfigForeignKeys(Schema $schema) * * @param Schema $schema */ - protected function addOroPaymentMethodsConfigsRuleForeignKeys(Schema $schema) + protected function addMarelloPaymentMethodsConfigsRuleForeignKeys(Schema $schema) { $table = $schema->getTable('marello_payment_mtds_cfgs_rl'); $table->addForeignKeyConstraint( @@ -144,7 +144,7 @@ protected function addOroPaymentMethodsConfigsRuleForeignKeys(Schema $schema) * * @param Schema $schema */ - protected function addOroPaymentMethodsConfigsRuleDestinationForeignKeys(Schema $schema) + protected function addMarelloPaymentMethodsConfigsRuleDestinationForeignKeys(Schema $schema) { $table = $schema->getTable('marello_payment_mtds_cfgs_rl_d'); $table->addForeignKeyConstraint( @@ -172,7 +172,7 @@ protected function addOroPaymentMethodsConfigsRuleDestinationForeignKeys(Schema * * @param Schema $schema */ - protected function addOroPaymentMethodsConfigsRuleDestinationPostalCodeForeignKeys(Schema $schema) + protected function addMarelloPaymentMethodsConfigsRuleDestinationPostalCodeForeignKeys(Schema $schema) { $table = $schema->getTable('marello_pmnt_mtdscfgsrl_dst_pc'); $table->addForeignKeyConstraint( diff --git a/src/Marello/Bundle/PaymentBundle/Migrations/Schema/v2_0/MarelloPaymentBundle.php b/src/Marello/Bundle/PaymentBundle/Migrations/Schema/v2_0/MarelloPaymentBundle.php new file mode 100644 index 000000000..37c9f97fa --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Migrations/Schema/v2_0/MarelloPaymentBundle.php @@ -0,0 +1,97 @@ +createMarelloPaymentPaymentTable($schema); + + $this->addMarelloPaymentPaymentForeignKeys($schema); + } + + /** + * Create marello_payment_payment table + * + * @param Schema $schema + */ + protected function createMarelloPaymentPaymentTable(Schema $schema) + { + $table = $schema->createTable('marello_payment_payment'); + $table->addColumn('id', 'integer', ['autoincrement' => true]); + $table->addColumn('organization_id', 'integer', ['notnull' => false]); + $table->addColumn('payment_method', 'string', ['notnull' => false, 'length' => 255]); + $table->addColumn( + 'payment_method_options', + 'json_array', + [ + 'notnull' => false, 'comment' => '(DC2Type:json_array)' + ] + ); + $table->addColumn('payment_reference', 'string', ['notnull' => false, 'length' => 255]); + $table->addColumn('payment_details', 'text', ['notnull' => false]); + $table->addColumn('total_paid', 'money', ['precision' => 19, 'scale' => 4, 'comment' => '(DC2Type:money)']); + $table->addColumn('payment_date', 'datetime', ['notnull' => false, 'comment' => '(DC2Type:datetime)']); + $table->addColumn('currency', 'string', ['notnull' => false, 'length' => 10]); + $table->addColumn('created_at', 'datetime'); + $table->addColumn('updated_at', 'datetime', ['notnull' => false]); + $this->extendExtension->addEnumField( + $schema, + $table, + 'status', + 'marello_paymnt_status', + false, + false, + [ + 'extend' => ['owner' => ExtendScope::OWNER_SYSTEM], + ] + ); + $table->setPrimaryKey(['id']); + $table->addIndex(['organization_id']); + } + + /** + * Add marello_payment_payment foreign keys. + * + * @param Schema $schema + */ + protected function addMarelloPaymentPaymentForeignKeys(Schema $schema) + { + $table = $schema->getTable('marello_payment_payment'); + $table->addForeignKeyConstraint( + $schema->getTable('oro_organization'), + ['organization_id'], + ['id'], + ['onDelete' => 'SET NULL', 'onUpdate' => null] + ); + } + + /** + * Sets the ExtendExtension + * + * @param ExtendExtension $extendExtension + */ + public function setExtendExtension(ExtendExtension $extendExtension) + { + $this->extendExtension = $extendExtension; + } +} diff --git a/src/Marello/Bundle/PaymentBundle/Model/ExtendPayment.php b/src/Marello/Bundle/PaymentBundle/Model/ExtendPayment.php new file mode 100644 index 000000000..6383964d9 --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Model/ExtendPayment.php @@ -0,0 +1,10 @@ +localeSettings = $localeSettings; + $this->currencyListProvider = $currencyListProvider; + } + + /** + * @inheritDoc + */ + public function processFormChanges(FormChangeContextInterface $context) + { + $form = $context->getForm(); + $invoice = $form->get('paymentSource')->getData(); + $result = $context->getResult(); + $currencyChoices = []; + if ($invoice instanceof AbstractInvoice) { + $currencyChoices[$this->localeSettings->getCurrencySymbolByCurrency($invoice->getCurrency())] = + $invoice->getCurrency(); + } else { + foreach ($this->currencyListProvider->getCurrencyList() as $currency) { + $currencyChoices[$this->localeSettings->getCurrencySymbolByCurrency($currency)] = + $currency; + } + } + $result[self::FIELD] = $currencyChoices; + $context->setResult($result); + } +} diff --git a/src/Marello/Bundle/PaymentBundle/Provider/FormChanges/AvailablePaymentMethodsFormChangesProvider.php b/src/Marello/Bundle/PaymentBundle/Provider/FormChanges/AvailablePaymentMethodsFormChangesProvider.php new file mode 100644 index 000000000..cd3f52dbf --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Provider/FormChanges/AvailablePaymentMethodsFormChangesProvider.php @@ -0,0 +1,108 @@ +templatingEngine = $templatingEngine; + $this->formFactory = $formFactory; + $this->paymentMethodChoicesProvider = $paymentMethodChoicesProvider; + } + + /** + * {@inheritdoc} + */ + public function processFormChanges(FormChangeContextInterface $context) + { + $form = $context->getForm(); + if ($form->has('paymentMethod')) { + $paymentFormName = $form->getName(); + $paymentSource = $form->get('paymentSource')->getData(); + if ($paymentSource instanceof AbstractInvoice) { + $sourcePaymentMethod = $paymentSource->getPaymentMethod(); + if ($sourcePaymentMethod) { + $allPaymentMethods = $this->paymentMethodChoicesProvider->getMethods(); + $choices = [$allPaymentMethods[$sourcePaymentMethod] => $sourcePaymentMethod]; + $form = $this->formFactory + ->createNamedBuilder($paymentFormName) + ->add( + 'paymentMethod', + PaymentMethodSelectType::class, + [ + 'label' => 'marello.payment.payment_method.label', + 'required' => true, + 'choices' => $choices, + 'constraints' => new NotNull, + ] + ) + ->getForm(); + } + } else { + $form = $this->formFactory + ->createNamedBuilder($paymentFormName) + ->add( + 'paymentMethod', + PaymentMethodSelectType::class, + [ + 'label' => 'marello.payment.payment_method.label', + 'required' => true, + 'constraints' => new NotNull, + ] + ) + ->getForm(); + } + + $result = $context->getResult(); + $result[self::FIELD] = $this->renderForm($form->createView()); + $context->setResult($result); + } + } + + /** + * @param FormView $formView + * @return string + */ + protected function renderForm(FormView $formView) + { + return $this + ->templatingEngine + ->render('MarelloPaymentBundle:Form:paymentMethodSelector.html.twig', ['form' => $formView]); + } +} diff --git a/src/Marello/Bundle/PaymentBundle/Resources/config/jsmodules.yml b/src/Marello/Bundle/PaymentBundle/Resources/config/jsmodules.yml index 93452c960..fbf99e521 100644 --- a/src/Marello/Bundle/PaymentBundle/Resources/config/jsmodules.yml +++ b/src/Marello/Bundle/PaymentBundle/Resources/config/jsmodules.yml @@ -1,3 +1,6 @@ dynamic-imports: marellopayment: - - marellopayment/js/app/views/payment-rule-method-view \ No newline at end of file + - marellopayment/js/app/views/payment-rule-method-view + - marellopayment/js/app/views/payment-method-view + - marellopayment/js/app/views/payment-source-view + - marellopayment/js/app/views/total-paid-view \ No newline at end of file diff --git a/src/Marello/Bundle/PaymentBundle/Resources/config/oro/datagrids.yml b/src/Marello/Bundle/PaymentBundle/Resources/config/oro/datagrids.yml index 84a10c2fb..faab6b0f0 100644 --- a/src/Marello/Bundle/PaymentBundle/Resources/config/oro/datagrids.yml +++ b/src/Marello/Bundle/PaymentBundle/Resources/config/oro/datagrids.yml @@ -106,3 +106,166 @@ datagrids: icon: close entity_name: 'Marello\Bundle\PaymentBundle\Entity\PaymentMethodsConfigsRule' data_identifier: payment_methods_configs_rule.id + + marello-payments-base-grid: + source: + type: orm + query: + select: + - p.id + - p.paymentMethod + - p.paymentMethodOptions + - p.paymentReference + - p.paymentDetails + - p.paymentDate + - p.totalPaid + - p.createdAt + - p.updatedAt + - p.currency + - s.name AS status + columns: + status: + label: marello.payment.status.label + frontend_type: string + data_name: status + paymentMethod: + label: marello.payment.payment_method.label + type: twig + frontend_type: html + template: MarelloPaymentBundle:Payment/Datagrid:paymentMethodWithoutOptions.html.twig + paymentReference: + label: marello.payment.payment_reference.label + frontend_type: string + paymentDetails: + label: marello.payment.payment_details.label + frontend_type: string + paymentDate: + frontend_type: datetime + label: marello.payment.payment_date.label + createdAt: + label: oro.ui.created_at + frontend_type: datetime + updatedAt: + label: oro.ui.updated_at + frontend_type: datetime + totalPaid: + label: marello.payment.total_paid.label + type: localized_number + method: formatCurrency + context_resolver: Marello\Bundle\DataGridBundle\Grid\FormatterContextResolver::getResolverCurrencyClosure + align: right + sorters: + columns: + status: + data_name: s.name + paymentMethod: + data_name: p.paymentMethod + paymentReference: + data_name: p.paymentReference + paymentDetails: + data_name: p.paymentDetails + totalPaid: + data_name: p.totalPaid + paymentDate: + data_name: p.paymentDate + createdAt: + data_name: p.createdAt + updatedAt: + data_name: p.updatedAt + default: + createdAt: 'DESC' + filters: + columns: + status: + type: string + data_name: s.name + paymentMethod: + type: string + data_name: p.paymentMethod + paymentReference: + type: string + data_name: p.paymentReference + paymentDetails: + type: string + data_name: p.paymentDetails + totalPaid: + type: number + data_name: p.totalPaid + properties: + id: ~ + view_link: + type: url + route: marello_payment_view + params: [ id ] + update_link: + type: url + route: marello_payment_update + params: [ id ] + actions: + view: + type: navigate + label: oro.grid.action.view + link: view_link + icon: eye + acl_recource: marello_payment_view + rowAction: true + update: + type: navigate + label: oro.grid.action.update + icon: edit + link: update_link + acl_resource: marello_payment_update + + marello-payments-grid: + extends: marello-payments-base-grid + source: + type: orm + query: + from: + - { table: MarelloPaymentBundle:Payment, alias: p } + join: + inner: + - { join: p.status, alias: s } + + marello-order-payments-grid: + extends: marello-payments-base-grid + source: + type: orm + query: + from: + - { table: MarelloInvoiceBundle:AbstractInvoice, alias: i } + join: + inner: + - { join: i.payments, alias: p } + - { join: p.status, alias: s } + - { join: i.order, alias: o } + where: + and: + - o.id = :orderId + bind_parameters: + - orderId + options: + entityHint: marello.payment.entity_plural_label + gridViews: + allLabel: marello.payment.entity_plural_label + + marello-invoice-payments-grid: + extends: marello-payments-base-grid + source: + type: orm + query: + from: + - { table: MarelloInvoiceBundle:AbstractInvoice, alias: i } + join: + inner: + - { join: i.payments, alias: p } + - { join: p.status, alias: s } + where: + and: + - i.id = :invoiceId + bind_parameters: + - invoiceId + options: + entityHint: marello.payment.entity_plural_label + gridViews: + allLabel: marello.payment.entity_plural_label \ No newline at end of file diff --git a/src/Marello/Bundle/PaymentBundle/Resources/config/oro/navigation.yml b/src/Marello/Bundle/PaymentBundle/Resources/config/oro/navigation.yml index 1d398ce07..ca400e9db 100644 --- a/src/Marello/Bundle/PaymentBundle/Resources/config/oro/navigation.yml +++ b/src/Marello/Bundle/PaymentBundle/Resources/config/oro/navigation.yml @@ -1,6 +1,13 @@ navigation: menu_config: items: + marello_payments: + label: 'marello.payment.entity_plural_label' + route: 'marello_payment_index' + extras: + routes: ['marello_payment_*'] + position: 45 + marello_payment_rules: label: 'marello.payment.menu.paymentmethodsconfigsrule.label' route: 'marello_payment_methods_configs_rule_index' @@ -18,6 +25,9 @@ navigation: tree: application_menu: children: + sales_tab: + children: + marello_payments: ~ system_tab: children: marello_payment_rules: ~ @@ -26,6 +36,7 @@ navigation: shortcut_marello_payment_rules: ~ titles: + marello_payment_index: 'marello.payment.entity_plural_label' marello_payment_methods_configs_rule_index: ~ marello_payment_methods_configs_rule_view: '%label%' marello_payment_methods_configs_rule_update: 'Payment Rule %id% - Edit' diff --git a/src/Marello/Bundle/PaymentBundle/Resources/config/oro/routing.yml b/src/Marello/Bundle/PaymentBundle/Resources/config/oro/routing.yml index 05cfefb5c..9bef6599e 100644 --- a/src/Marello/Bundle/PaymentBundle/Resources/config/oro/routing.yml +++ b/src/Marello/Bundle/PaymentBundle/Resources/config/oro/routing.yml @@ -1,3 +1,13 @@ +marello_payment: + resource: "@MarelloPaymentBundle/Controller/PaymentController.php" + type: annotation + prefix: /marello/payment + +marello_payment_ajax: + resource: "@MarelloPaymentBundle/Controller/PaymentAjaxController.php" + type: annotation + prefix: /marello/payment + marello_payment_methods_configs_rule: resource: "@MarelloPaymentBundle/Controller/PaymentMethodsConfigsRuleController.php" type: annotation diff --git a/src/Marello/Bundle/PaymentBundle/Resources/config/services.yml b/src/Marello/Bundle/PaymentBundle/Resources/config/services.yml index 676361ab8..1f8547ede 100644 --- a/src/Marello/Bundle/PaymentBundle/Resources/config/services.yml +++ b/src/Marello/Bundle/PaymentBundle/Resources/config/services.yml @@ -22,6 +22,49 @@ services: - '@request_stack' - '@doctrine.orm.entity_manager' + marello_payment.form.type.payment_create: + class: 'Marello\Bundle\PaymentBundle\Form\Type\PaymentCreateType' + arguments: + - '@doctrine' + - '@marello_payment.provider.basic_payment_methods_choices' + tags: + - { name: form.type } + + marello_payment.form.payment_create: + class: 'Symfony\Component\Form\Form' + factory: ['@form.factory', 'create'] + arguments: + - 'Marello\Bundle\PaymentBundle\Form\Type\PaymentCreateType' + + marello_payment.form.handler.payment_create: + class: 'Marello\Bundle\PaymentBundle\Form\Handler\PaymentCreateHandler' + public: true + arguments: + - '@marello_payment.form.payment_create' + - '@request_stack' + - '@doctrine.orm.entity_manager' + + marello_payment.form.type.payment_update: + class: 'Marello\Bundle\PaymentBundle\Form\Type\PaymentUpdateType' + arguments: + - '@doctrine' + tags: + - { name: form.type } + + marello_payment.form.payment_update: + class: 'Symfony\Component\Form\Form' + factory: ['@form.factory', 'create'] + arguments: + - 'Marello\Bundle\PaymentBundle\Form\Type\PaymentUpdateType' + + marello_payment.form.handler.payment_update: + class: 'Marello\Bundle\PaymentBundle\Form\Handler\PaymentUpdateHandler' + public: true + arguments: + - '@marello_payment.form.payment_update' + - '@request_stack' + - '@doctrine.orm.entity_manager' + marello_payment.datagrid.payment_rule_actions_visibility_provider: parent: marello_rule.action.visibility_provider public: true @@ -94,6 +137,13 @@ services: tags: - { name: kernel.event_listener, event: marello_payment.method_renaming, method: onMethodRename} + marello_orderpayment.event_listener.payment_creation: + class: 'Marello\Bundle\PaymentBundle\EventListener\PaymentCreationListener' + arguments: + - '@oro_entity.doctrine_helper' + tags: + - { name: kernel.event_listener, event: extendable_action.order_paid, method: onOrderPaid } + marello_payment.method.event.dispatcher.method_removal: class: 'Marello\Bundle\PaymentBundle\Method\Event\BasicMethodRemovalEventDispatcher' public: false @@ -193,6 +243,13 @@ services: - '@marello_payment.repository.payment_methods_configs_rule' - '@marello_payment.payment_method.composite_provider' + marello_payment.action.handler.add_payment: + class: 'Marello\Bundle\PaymentBundle\Action\Handler\AddPaymentActionHandler' + public: true + arguments: + - '@doctrine.orm.entity_manager' + - '@marello_invoice.provider.invoice_paid_amount' + marello_payment.action.handler.payment_methods_configs_rule.enable_status: class: 'Marello\Bundle\PaymentBundle\Action\Handler\PaymentMethodsConfigsRuleToggleStatusActionHandler' public: true @@ -246,3 +303,30 @@ services: - '%marello_payment.rule_grid_route_name%' - '%marello_payment.rule_grid_name%' - '@oro_datagrid.helper.route' + + marello_payment.provider.form_changes.available_currencies: + class: 'Marello\Bundle\PaymentBundle\Provider\FormChanges\AvailableCurrenciesFormChangesProvider' + arguments: + - '@oro_locale.settings' + - '@oro_currency.config.currency' + tags: + - { name: marello.form_changes_data_provider, class: 'Marello\Bundle\PaymentBundle\Entity\Payment', type: currencies, priority: 45 } + + marello_payment.provider.form_changes.available_payment_methods: + class: 'Marello\Bundle\PaymentBundle\Provider\FormChanges\AvailablePaymentMethodsFormChangesProvider' + arguments: + - '@templating' + - '@form.factory' + - '@marello_payment.provider.basic_payment_methods_choices' + tags: + - { name: marello.form_changes_data_provider, class: 'Marello\Bundle\PaymentBundle\Entity\Payment', type: paymentMethods, priority: 45 } + + marello_payment.validator.payment_status: + class: 'Marello\Bundle\PaymentBundle\Validator\PaymentStatusValidator' + tags: + - { name: validator.constraint_validator, alias: marello_payment.payment_status_validator } + + marello_payment.validator.total_paid: + class: 'Marello\Bundle\PaymentBundle\Validator\TotalPaidValidator' + tags: + - { name: validator.constraint_validator, alias: marello_payment.total_paid_validator } diff --git a/src/Marello/Bundle/PaymentBundle/Resources/config/validation.yml b/src/Marello/Bundle/PaymentBundle/Resources/config/validation.yml index 44f612feb..18ac20bb6 100644 --- a/src/Marello/Bundle/PaymentBundle/Resources/config/validation.yml +++ b/src/Marello/Bundle/PaymentBundle/Resources/config/validation.yml @@ -25,3 +25,8 @@ Marello\Bundle\PaymentBundle\Entity\PaymentMethodConfig: properties: method: - NotBlank: ~ + +Marello\Bundle\PaymentBundle\Entity\Payment: + constraints: + - Marello\Bundle\PaymentBundle\Validator\Constraints\PaymentStatus: ~ + - Marello\Bundle\PaymentBundle\Validator\Constraints\TotalPaid: ~ \ No newline at end of file diff --git a/src/Marello/Bundle/PaymentBundle/Resources/public/css/scss/style.scss b/src/Marello/Bundle/PaymentBundle/Resources/public/css/scss/style.scss index 688715028..efd6aa20f 100755 --- a/src/Marello/Bundle/PaymentBundle/Resources/public/css/scss/style.scss +++ b/src/Marello/Bundle/PaymentBundle/Resources/public/css/scss/style.scss @@ -48,3 +48,10 @@ .marello-payment-rule-add-method-select { display: inline-block; } + +.marello-payment-update-property-label { + max-width: 180px; + color: #545456; + margin-right: 12px; +} + diff --git a/src/Marello/Bundle/PaymentBundle/Resources/public/js/app/views/payment-method-view.js b/src/Marello/Bundle/PaymentBundle/Resources/public/js/app/views/payment-method-view.js new file mode 100755 index 000000000..3fe27fe45 --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Resources/public/js/app/views/payment-method-view.js @@ -0,0 +1,90 @@ +define(function(require) { + 'use strict'; + + const $ = require('jquery'); + const _ = require('underscore'); + const mediator = require('oroui/js/mediator'); + const LoadingMaskView = require('oroui/js/app/views/loading-mask-view'); + const BaseView = require('oroui/js/app/views/base/view'); + + /** + * @export marelloorder/js/app/views/order-totals-view + * @extends oroui.app.views.base.View + * @class marelloorder.app.views.OrderTotalsView + */ + const PaymentMethodView = BaseView.extend({ + /** + * @property {LoadingMaskView} + */ + loadingMaskView: null, + + /** + * @inheritDoc + */ + initialize: function(options) { + this.options = _.defaults(options || {}, this.options); + + this.loadingMaskView = new LoadingMaskView({container: this.$el}); + + mediator.on('payment:form-changes:trigger', this.loadingStart, this); + mediator.on('payment:form-changes:load', this.updatePaymentMethods, this); + mediator.on('payment:form-changes:load:after', this.loadingEnd, this); + }, + + /** + * @param {Object} data + */ + updatePaymentMethods: function(data) { + var paymentMethodsHtml = data['paymentMethods'] || null; + if (!paymentMethodsHtml) { + this.loadingEnd(); + return; + } + + this.render(paymentMethodsHtml); + }, + + /** + * Show loading view + */ + loadingStart: function(e) { + if (e.updateFields !== undefined && _.contains(e.updateFields, "paymentMethods") !== true) { + return; + } + this.loadingMaskView.show(); + }, + + /** + * Hide loading view + */ + loadingEnd: function() { + this.loadingMaskView.hide(); + }, + + /** + * Render + * + * @param {String} paymentMethodHtml + */ + render: function(paymentMethodHtml) { + $("div[data-ftid='marello_payment_create_paymentMethod']").replaceWith(paymentMethodHtml); + }, + + /** + * @inheritDoc + */ + dispose: function() { + if (this.disposed) { + return; + } + + mediator.off('payment:form-changes:trigger', this.loadingStart, this); + mediator.off('payment:form-changes:load', this.updatePaymentMethods, this); + mediator.off('payment:form-changes:load:after', this.loadingEnd, this); + + PaymentMethodView.__super__.dispose.call(this); + } + }); + + return PaymentMethodView; +}); diff --git a/src/Marello/Bundle/PaymentBundle/Resources/public/js/app/views/payment-source-view.js b/src/Marello/Bundle/PaymentBundle/Resources/public/js/app/views/payment-source-view.js new file mode 100755 index 000000000..75867494e --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Resources/public/js/app/views/payment-source-view.js @@ -0,0 +1,51 @@ +define(function(require) { + 'use strict'; + + const $ = require('jquery'); + const _ = require('underscore'); + const mediator = require('oroui/js/mediator'); + const BaseView = require('oroui/js/app/views/base/view'); + + /** + * @export marelloorder/js/app/views/order-discount-view + * @extends oroui.app.views.base.View + * @class marelloorder.app.views.OrderDiscountView + */ + const OrderDiscountView = BaseView.extend({ + /** + * @property {Object} + */ + options: {}, + + /** + * @property {jQuery} + */ + $field: null, + + /** + * @inheritDoc + */ + initialize: function(options) { + this.options = $.extend(true, {}, this.options, options || {}); + + this.$field = this.$el.find(':input[data-ftid]'); + $(this.$field).on('change', function() { + mediator.trigger('payment:form-changes:trigger', {updateFields: ['paymentMethods', 'currencies']}); + }); + $(this.$field).trigger('change'); + }, + + /** + * @inheritDoc + */ + dispose: function() { + if (this.disposed) { + return; + } + + OrderDiscountView.__super__.dispose.call(this); + } + }); + + return OrderDiscountView; +}); diff --git a/src/Marello/Bundle/PaymentBundle/Resources/public/js/app/views/total-paid-view.js b/src/Marello/Bundle/PaymentBundle/Resources/public/js/app/views/total-paid-view.js new file mode 100755 index 000000000..d4bf44e33 --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Resources/public/js/app/views/total-paid-view.js @@ -0,0 +1,98 @@ +define(function(require) { + 'use strict'; + + const $ = require('jquery'); + const _ = require('underscore'); + const mediator = require('oroui/js/mediator'); + const LoadingMaskView = require('oroui/js/app/views/loading-mask-view'); + const BaseView = require('oroui/js/app/views/base/view'); + + /** + * @export marelloorder/js/app/views/order-totals-view + * @extends oroui.app.views.base.View + * @class marelloorder.app.views.OrderTotalsView + */ + const TotalPaidCurrenciesView = BaseView.extend({ + /** + * @property {LoadingMaskView} + */ + loadingMaskView: null, + + /** + * @inheritDoc + */ + initialize: function(options) { + this.options = _.defaults(options || {}, this.options); + + this.loadingMaskView = new LoadingMaskView({container: this.$el}); + + mediator.on('payment:form-changes:trigger', this.loadingStart, this); + mediator.on('payment:form-changes:load', this.updateCurrencies, this); + mediator.on('payment:form-changes:load:after', this.loadingEnd, this); + }, + + /** + * @param {Object} data + */ + updateCurrencies: function(data) { + var currencies = data['currencies'] || null; + if (!currencies) { + this.loadingEnd(); + return; + } + + this.render(currencies); + }, + + /** + * Show loading view + */ + loadingStart: function(e) { + if (e.updateFields !== undefined && _.contains(e.updateFields, "currencies") !== true) { + return; + } + this.loadingMaskView.show(); + }, + + /** + * Hide loading view + */ + loadingEnd: function() { + this.loadingMaskView.hide(); + }, + + /** + * Render + * + * @param {Object} currencies + */ + render: function(currencies) { + var selector = $("select[name='marello_payment_create[totalPaid][currency]']"); + selector.empty(); + $.each(currencies, function(text, value) { + var option = $("") + .attr("value", value) + .text(text); + selector.append(option); + }); + selector.trigger('change'); + }, + + /** + * @inheritDoc + */ + dispose: function() { + if (this.disposed) { + return; + } + + mediator.off('payment:form-changes:trigger', this.loadingStart, this); + mediator.off('payment:form-changes:load', this.updateCurrencies, this); + mediator.off('payment:form-changes:load:after', this.loadingEnd, this); + + TotalPaidCurrenciesView.__super__.dispose.call(this); + } + }); + + return TotalPaidCurrenciesView; +}); diff --git a/src/Marello/Bundle/PaymentBundle/Resources/translations/messages.en.yml b/src/Marello/Bundle/PaymentBundle/Resources/translations/messages.en.yml index 7a4ae474d..a6bddbcbc 100644 --- a/src/Marello/Bundle/PaymentBundle/Resources/translations/messages.en.yml +++ b/src/Marello/Bundle/PaymentBundle/Resources/translations/messages.en.yml @@ -1,5 +1,23 @@ marello: payment: + entity_label: Payment + entity_plural_label: Payments + entity_grid_all_view_label: All %entity_plural_label% + id.label: Id + organization.label: Organization + payment_method.label: Payment Method + payment_method_options.label: Payment Method Options + payment_reference.label: Payment Reference + payment_details.label: Payment Details + payment_source.label: Related Entity + payment_date.label: Payment Date + total_paid.label: Total Paid + currency.label: Currency + status.label: Status + + button: + add_payment.label: Add Payment + menu: payments.label: Payments paymentmethodsconfigsrule.description: Payment Rules @@ -70,6 +88,10 @@ marello: message: error: 'General error. We were unable to process action.' + add_payment: + success: 'Payment was successfuly added' + error: + paid_total_exceed: "Total Paid amount of all Payments can't exceed Invoice grandTotal amount" paymentmethodconfig: entity_label: Payment Method Config @@ -148,7 +170,8 @@ marello: pending.label: Pending sections: - general: 'General Information' + general: 'General' + additional: 'Additional' destination: 'Destinations' paymentrule_configurations: no_methods.message: 'Please enable at least one payment integration.' diff --git a/src/Marello/Bundle/PaymentBundle/Resources/translations/validators.en.yml b/src/Marello/Bundle/PaymentBundle/Resources/translations/validators.en.yml index 4a433c817..27bb946d6 100644 --- a/src/Marello/Bundle/PaymentBundle/Resources/translations/validators.en.yml +++ b/src/Marello/Bundle/PaymentBundle/Resources/translations/validators.en.yml @@ -4,3 +4,5 @@ marello: paymentrule: type.config.count.message: 'You must select at least {{ limit }} payment method type|You must select at least {{ limit }} payment method types' method.config.count.message: 'You must select at least {{ limit }} payment method|You must select at least {{ limit }} payment methods' + status.message: 'Only payments with related entity can have status "Assigned" and only payments without related entity can have status "Unassigned"' + total_paid.message: "Total Paid can't be higher related entity's Total Due" \ No newline at end of file diff --git a/src/Marello/Bundle/PaymentBundle/Resources/views/Action/payment_popup.html.twig b/src/Marello/Bundle/PaymentBundle/Resources/views/Action/payment_popup.html.twig new file mode 100644 index 000000000..af5ef2e24 --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Resources/views/Action/payment_popup.html.twig @@ -0,0 +1,22 @@ +{% extends 'OroActionBundle:Operation:form.html.twig' %} + +{% block form %} + {% set buttonOptions = operation.definition.buttonOptions %} +
+ {{ form_start(form, {'action': app.request.uri, 'attr': {'id': form.vars.id, 'data-collect': 'true', 'class': 'form-dialog'}}) }} +
+ {{ form_row(form.payment_method) }} + {{ form_row(form.payment_date) }} + {{ form_row(form.payment_reference) }} + {{ form_row(form.payment_details) }} + {{ form_row(form.total_paid) }} +
+
+ + +
+ {{ form_rest(form) }} + {{ form_end(form) }} + {{ oro_form_js_validation(form) }} +
+{% endblock %} diff --git a/src/Marello/Bundle/PaymentBundle/Resources/views/Form/paymentMethodSelector.html.twig b/src/Marello/Bundle/PaymentBundle/Resources/views/Form/paymentMethodSelector.html.twig new file mode 100755 index 000000000..6968a36de --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Resources/views/Form/paymentMethodSelector.html.twig @@ -0,0 +1 @@ +{{ form_widget(form.paymentMethod) }} diff --git a/src/Marello/Bundle/PaymentBundle/Resources/views/Payment/Datagrid/paymentMethodWithOptions.html.twig b/src/Marello/Bundle/PaymentBundle/Resources/views/Payment/Datagrid/paymentMethodWithOptions.html.twig new file mode 100644 index 000000000..e73786090 --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Resources/views/Payment/Datagrid/paymentMethodWithOptions.html.twig @@ -0,0 +1,8 @@ +{% spaceless %} + {% set identifier = record.getValue('paymentMethod') %} + {% set options = record.getValue('paymentMethodOptions') %} + {{ marello_get_payment_method_label(identifier)|trans }}
+ {% for name, value in options %} + {{ name ~ ': ' ~ value }}
+ {% endfor %} +{% endspaceless %} diff --git a/src/Marello/Bundle/PaymentBundle/Resources/views/Payment/Datagrid/paymentMethodWithoutOptions.html.twig b/src/Marello/Bundle/PaymentBundle/Resources/views/Payment/Datagrid/paymentMethodWithoutOptions.html.twig new file mode 100644 index 000000000..06197dfec --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Resources/views/Payment/Datagrid/paymentMethodWithoutOptions.html.twig @@ -0,0 +1,4 @@ +{% spaceless %} + {% set identifier = record.getValue('paymentMethod') %} + {{ marello_get_payment_method_label(identifier)|trans }} +{% endspaceless %} diff --git a/src/Marello/Bundle/PaymentBundle/Resources/views/Payment/create.html.twig b/src/Marello/Bundle/PaymentBundle/Resources/views/Payment/create.html.twig new file mode 100644 index 000000000..956b93214 --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Resources/views/Payment/create.html.twig @@ -0,0 +1,96 @@ +{% extends 'OroUIBundle:actions:update.html.twig' %} +{% import 'OroUIBundle::macros.html.twig' as UI %} +{% import 'OroDataGridBundle::macros.html.twig' as dataGrid %} +{% form_theme form with 'OroFormBundle:Form:fields.html.twig' %} +{% set formAction = path('marello_payment_create') %} + +{% block navButtons %} + {{ UI.cancelButton(path('marello_payment_index')) }} + {% set html = UI.saveAndCloseButton({ + 'route': 'marello_payment_index' + }) %} + {{ UI.dropdownSaveButton({ 'html': html }) }} +{% endblock navButtons %} + +{% block pageHeader %} + {% set title = 'oro.ui.create_entity'|trans({'%entityName%': 'marello.payment.entity_label'|trans}) %} + {% include 'OroUIBundle::page_title_block.html.twig' with { title: title } %} +{% endblock pageHeader %} + +{% set pageComponent = { + module: 'marellolayout/js/app/components/form-changes-component', + options: { + route: 'marello_payment_form_changes', + prefix: 'payment', + routeParams: {id: entity.id|default(0)} + } +} %} + +{% block content_data %} + {% set id = 'marello-payment-create' %} + {% set generalSubblocks = [] %} + {% set generalInformation %} +
+
+
+
+
+ {{ form_row(form.paymentSource) }} +
+
+ {{ form_row(form.paymentMethod) }} +
+ {{ form_row(form.paymentDate) }} + {{ form_row(form.paymentReference) }} + {{ form_row(form.paymentDetails) }} +
+ {{ form_row(form.totalPaid) }} +
+
+
+
+
+ {% endset %} + {% set generalSubblocks = generalSubblocks|merge([{'data' : [generalInformation] }]) %} + + + {% set dataBlocks = [{ + 'title': 'marello.payment.sections.general'|trans, + 'class': 'active', + 'subblocks': generalSubblocks + } + ] %} + + {% set additionalData = [] %} + {% for child in form.children if child.vars.extra_field is defined and child.vars.extra_field %} + {% set additionalData = additionalData|merge([form_row(child)]) %} + {% endfor %} + + {% if additionalData is not empty %} + {% set dataBlocks = dataBlocks|merge([{ + 'title' : 'marello.payment.sections.additional'|trans, + 'subblocks': [{ + 'title' : null, + 'useSpan': false, + 'data' : [ + additionalData + ] + }] + }]) %} + {% endif %} + + {% set data = { + 'formErrors': form_errors(form)? form_errors(form) : null, + 'dataBlocks': dataBlocks, + } %} + {{ parent() }} +{% endblock content_data %} diff --git a/src/Marello/Bundle/PaymentBundle/Resources/views/Payment/index.html.twig b/src/Marello/Bundle/PaymentBundle/Resources/views/Payment/index.html.twig new file mode 100644 index 000000000..fa3ded544 --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Resources/views/Payment/index.html.twig @@ -0,0 +1,13 @@ +{% extends 'OroUIBundle:actions:index.html.twig' %} +{% import 'OroUIBundle::macros.html.twig' as UI %} +{% set gridName = 'marello-payments-grid' %} +{% set pageTitle = 'marello.payment.entity_plural_label'|trans %} + +{% block navButtons %} + {% if is_granted('marello_payment_create') %} + {{ UI.addButton({ + 'path': path('marello_payment_create'), + 'entity_label': 'marello.payment.entity_label'|trans + }) }} + {% endif %} +{% endblock %} \ No newline at end of file diff --git a/src/Marello/Bundle/PaymentBundle/Resources/views/Payment/update.html.twig b/src/Marello/Bundle/PaymentBundle/Resources/views/Payment/update.html.twig new file mode 100644 index 000000000..54aea7fc7 --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Resources/views/Payment/update.html.twig @@ -0,0 +1,91 @@ +{% extends 'OroUIBundle:actions:update.html.twig' %} +{% import 'OroUIBundle::macros.html.twig' as UI %} +{% import 'OroDataGridBundle::macros.html.twig' as dataGrid %} +{% form_theme form with 'OroFormBundle:Form:fields.html.twig' %} +{% set formAction = path('marello_payment_update', { 'id': form.vars.value.id }) %} + +{% block navButtons %} + {{ parent() }} + + {{ UI.cancelButton(path('marello_payment_index')) }} + {% if is_granted('marello_payment_update') %} + {% set html = '' %} + {% if is_granted('marello_payment_view') %} + {% set html = UI.saveAndCloseButton({ + 'route': 'marello_payment_view', + 'params': {'id': '$id'} + }) %} + {% endif %} + {% set html = html ~ UI.saveAndStayButton({ + 'route': 'marello_payment_update', + 'params': {'id': '$id'} + }) %} + + {{ UI.dropdownSaveButton({'html': html}) }} + {% endif %} +{% endblock navButtons %} + +{% block pageHeader %} + {% set breadcrumbs = { + 'entity': form.vars.value, + 'indexPath': path('marello_payment_index'), + 'indexLabel': 'marello.payment.entity_plural_label'|trans, + 'entityTitle': entity.id + } %} + {{ parent() }} +{% endblock pageHeader %} + +{% block content_data %} + {% set id = 'marello-payment-update' %} + {% set paymentMethod = marello_get_payment_method_label(entity.paymentMethod)|trans %} + {% for name, value in entity.paymentMethodOptions %} + {% if name == 'term' %} + {% set value = 'marello.payment_term.ui.payment_term.term_days'|trans({'%days%': value }) %} + {% set name = 'Term' %} + {% elseif name == 'code' %} + {% set value = marello_get_payment_term_label_for_code(value) %} + {% set name = 'Label' %} + {% endif %} + {% set paymentMethod = paymentMethod ~ '
' ~ name ~ ': ' ~ value %} + {% endfor %} + {% set dataBlocks = [{ + 'title': 'marello.payment.sections.general'|trans, + 'class': 'active', + 'subblocks': [{ + 'title': '', + 'data': [ + form_row(form.status), + form_row(form.paymentSource), + UI.renderHtmlProperty('marello.payment.payment_method.label'|trans, paymentMethod, null, null, {termClass: 'marello-payment-update-property-label'}), + form_row(form.paymentReference), + form_row(form.paymentDetails), + UI.renderProperty('marello.payment.total_paid.label'|trans, entity.totalPaid|oro_format_currency({'currency':entity.currency}), null, null, {termClass: 'marello-payment-update-property-label'}), + UI.renderProperty('marello.payment.payment_date.label'|trans, entity.paymentDate|date, null, null, {termClass: 'marello-payment-update-property-label'}) + ] + }]} + ] %} + + {% set additionalData = [] %} + {% for child in form.children if child.vars.extra_field is defined and child.vars.extra_field %} + {% set additionalData = additionalData|merge([form_row(child)]) %} + {% endfor %} + + {% if additionalData is not empty %} + {% set dataBlocks = dataBlocks|merge([{ + 'title' : 'marello.payment.sections.additional'|trans, + 'subblocks': [{ + 'title' : null, + 'useSpan': false, + 'data' : [ + additionalData + ] + }] + }]) %} + {% endif %} + + {% set data = { + 'formErrors': form_errors(form)? form_errors(form) : null, + 'dataBlocks': dataBlocks, + } %} + {{ parent() }} +{% endblock content_data %} diff --git a/src/Marello/Bundle/PaymentBundle/Resources/views/Payment/view.html.twig b/src/Marello/Bundle/PaymentBundle/Resources/views/Payment/view.html.twig new file mode 100644 index 000000000..838e49826 --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Resources/views/Payment/view.html.twig @@ -0,0 +1,74 @@ +{% extends 'OroUIBundle:actions:view.html.twig' %} +{% import 'OroUIBundle::macros.html.twig' as UI %} + +{% block navButtons %} + {% if is_granted('marello_payment_update') %} + {{ UI.editButton({ + 'path' : path('marello_payment_update', { id: entity.id }), + 'entity_label': 'marello.payment.entity_label'|trans + }) }} + {% endif %} +{% endblock navButtons %} + +{% block pageHeader %} + {% set breadcrumbs = { + 'entity': entity, + 'indexPath': path('marello_payment_index'), + 'indexLabel': 'marello.payment.entity_plural_label'|trans, + 'entityTitle': entity.id + } %} + {{ parent() }} +{% endblock pageHeader %} + +{% block content_data %} + {% set id = 'marello-payment-view' %} + {% set paymentMethod = marello_get_payment_method_label(entity.paymentMethod)|trans %} + {% for name, value in entity.paymentMethodOptions %} + {% if name == 'term' %} + {% set value = 'marello.payment_term.ui.payment_term.term_days'|trans({'%days%': value }) %} + {% set name = 'Term' %} + {% elseif name == 'code' %} + {% set value = marello_get_payment_term_label_for_code(value) %} + {% set name = 'Label' %} + {% endif %} + {% set paymentMethod = paymentMethod ~ '
' ~ name ~ ': ' ~ value %} + {% endfor %} + {% set paymentSource = marello_get_payment_source(entity) %} + {% set data %} +
+
+
+ {{ UI.renderProperty('marello.payment.status.label'|trans, entity.status) }} + {% if paymentSource is not empty %} + {{ UI.renderHtmlProperty( + 'marello.payment.payment_source.label'|trans, + UI.entityViewLink(paymentSource, paymentSource.invoiceType ~ ': ' ~ paymentSource.invoiceNumber, 'marello_invoice_invoice_view') + )}} + {% else %} + {{ UI.renderHtmlProperty( + 'marello.payment.payment_source.label'|trans, + 'N/A' + )}} + {% endif %} + {{ UI.renderHtmlProperty('marello.payment.payment_method.label'|trans, paymentMethod) }} + {{ UI.renderProperty('marello.payment.payment_reference.label'|trans, entity.paymentReference) }} + {{ UI.renderProperty('marello.payment.payment_details.label'|trans, entity.paymentDetails) }} + {{ UI.renderProperty('marello.payment.total_paid.label'|trans, entity.totalPaid|oro_format_currency({'currency':entity.currency})) }} + {{ UI.renderProperty('marello.payment.payment_date.label'|trans, entity.paymentDate|date) }} +
+
+
+ {% endset %} + {% set dataBlocks = [ + { + 'title': 'General'|trans, + 'class': 'active', + 'subblocks': [ + { 'data' : [data] } + ] + } + ] %} + + {% set data = { 'dataBlocks': dataBlocks } %} + {{ parent() }} +{% endblock content_data %} diff --git a/src/Marello/Bundle/PaymentBundle/Validator/Constraints/PaymentStatus.php b/src/Marello/Bundle/PaymentBundle/Validator/Constraints/PaymentStatus.php new file mode 100644 index 000000000..26eca402c --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Validator/Constraints/PaymentStatus.php @@ -0,0 +1,27 @@ +getPaymentSource(); + $status = $entity->getStatus()->getId(); + if ((!$paymentSource && $status === LoadPaymentStatusData::ASSIGNED) || + ($paymentSource && $status === LoadPaymentStatusData::UNASSIGNED) + ) { + $this->context->buildViolation($constraint->message) + ->atPath('status') + ->addViolation(); + } + } + } +} diff --git a/src/Marello/Bundle/PaymentBundle/Validator/TotalPaidValidator.php b/src/Marello/Bundle/PaymentBundle/Validator/TotalPaidValidator.php new file mode 100644 index 000000000..ae9f55675 --- /dev/null +++ b/src/Marello/Bundle/PaymentBundle/Validator/TotalPaidValidator.php @@ -0,0 +1,38 @@ +getPaymentSource(); + if ($paymentSource) { + $totalPaid = $entity->getTotalPaid(); + $totalDue = $paymentSource->getTotalDue(); + if ($totalPaid > $totalDue) { + $this->context->buildViolation($constraint->message) + ->atPath('totalPaid') + ->addViolation(); + } + } + } + } +} diff --git a/src/Marello/Bundle/PaymentTermBundle/Provider/PaymentTermProvider.php b/src/Marello/Bundle/PaymentTermBundle/Provider/PaymentTermProvider.php index 569fb149d..512cd30b7 100644 --- a/src/Marello/Bundle/PaymentTermBundle/Provider/PaymentTermProvider.php +++ b/src/Marello/Bundle/PaymentTermBundle/Provider/PaymentTermProvider.php @@ -81,4 +81,15 @@ public function getPaymentTerms() { return $this->doctrineHelper->getEntityRepositoryForClass(PaymentTerm::class)->findAll(); } + + /** + * @param string $code + * @return PaymentTerm|null + */ + public function getPaymentTerm($code) + { + return $this->doctrineHelper + ->getEntityRepositoryForClass(PaymentTerm::class) + ->findOneBy(['code' => $code]); + } } diff --git a/src/Marello/Bundle/PaymentTermBundle/Resources/config/services.yml b/src/Marello/Bundle/PaymentTermBundle/Resources/config/services.yml index f6a0a5c2c..9b8523bc1 100644 --- a/src/Marello/Bundle/PaymentTermBundle/Resources/config/services.yml +++ b/src/Marello/Bundle/PaymentTermBundle/Resources/config/services.yml @@ -66,3 +66,12 @@ services: - '@marello_payment_term.provider.payment_term' tags: - { name: kernel.event_listener, event: marello_payment.applicable_payment_method_view, method: onApplicablePaymentMethodView } + + marello_payment_term.twig.payment_term_extension: + class: 'Marello\Bundle\PaymentTermBundle\Twig\PaymentTermExtension' + public: false + arguments: + - '@marello_payment_term.provider.payment_term' + - '@oro_locale.helper.localization' + tags: + - { name: twig.extension } diff --git a/src/Marello/Bundle/PaymentTermBundle/Twig/PaymentTermExtension.php b/src/Marello/Bundle/PaymentTermBundle/Twig/PaymentTermExtension.php new file mode 100755 index 000000000..d712bcb07 --- /dev/null +++ b/src/Marello/Bundle/PaymentTermBundle/Twig/PaymentTermExtension.php @@ -0,0 +1,71 @@ +paymentTermProvider = $paymentTermProvider; + $this->localizationHelper = $localizationHelper; + } + + + /** + * {@inheritdoc} + */ + public function getName() + { + return static::NAME; + } + + /** + * @return array + */ + public function getFunctions() + { + return [ + new TwigFunction( + 'marello_get_payment_term_label_for_code', + [$this, 'getPaymentTermLabelForCode'] + ), + new TwigFunction( + 'marello_get_payment_term_for_customer', + [$this->paymentTermProvider, 'getCustomerPaymentTerm'] + ) + ]; + } + + /** + * @param string $code + * @return string + */ + public function getPaymentTermLabelForCode($code) + { + $paymentTerm = $this->paymentTermProvider->getPaymentTerm($code); + if ($paymentTerm) { + return $this->localizationHelper->getLocalizedValue($paymentTerm->getLabels())->getString(); + } + } +} diff --git a/src/Marello/Bundle/PdfBundle/DependencyInjection/Configuration.php b/src/Marello/Bundle/PdfBundle/DependencyInjection/Configuration.php index 06d825b73..ce5c6eac7 100644 --- a/src/Marello/Bundle/PdfBundle/DependencyInjection/Configuration.php +++ b/src/Marello/Bundle/PdfBundle/DependencyInjection/Configuration.php @@ -22,6 +22,7 @@ class Configuration implements ConfigurationInterface const CONFIG_KEY_COMPANY_ADDRESS = 'company_address'; const CONFIG_KEY_COMPANY_EMAIL = 'company_email'; const CONFIG_KEY_LOGO = 'logo'; + const CONFIG_KEY_LOGO_WIDTH = 'logo_width'; const CONFIG_KEY_COMPANY_PHONE = 'company_phone'; const CONFIG_KEY_COMPANY_BANK = 'company_bank'; const CONFIG_KEY_COMPANY_COC = 'company_coc'; @@ -47,6 +48,7 @@ public function getConfigTreeBuilder() self::CONFIG_KEY_COMPANY_ADDRESS => ['value' => null], self::CONFIG_KEY_COMPANY_EMAIL => ['value' => null], self::CONFIG_KEY_LOGO => ['value' => null], + self::CONFIG_KEY_LOGO_WIDTH => ['value' => null], self::CONFIG_KEY_COMPANY_PHONE => ['value' => null], self::CONFIG_KEY_COMPANY_BANK => ['value' => null], self::CONFIG_KEY_COMPANY_COC => ['value' => null], diff --git a/src/Marello/Bundle/PdfBundle/Resources/config/oro/system_configuration.yml b/src/Marello/Bundle/PdfBundle/Resources/config/oro/system_configuration.yml index 9e3dd41bb..80853d463 100644 --- a/src/Marello/Bundle/PdfBundle/Resources/config/oro/system_configuration.yml +++ b/src/Marello/Bundle/PdfBundle/Resources/config/oro/system_configuration.yml @@ -55,6 +55,13 @@ system_configuration: fileConstraints: - Image: ~ + marello_pdf.logo_width: + data_type: number + type: 'Symfony\Component\Form\Extension\Core\Type\NumberType' + options: + label: marello.pdf.config.fields.logo_width.label + tooltip: marello.pdf.config.fields.logo_width.tooltip + marello_pdf.company_address: data_type: string type: 'Symfony\Component\Form\Extension\Core\Type\TextareaType' @@ -98,7 +105,7 @@ system_configuration: options: label: marello.pdf.config.fields.email_workflow_transition.label tooltip: marello.pdf.config.fields.email_workflow_transition.tooltip - workflow: marello_order_b2c_workflow_1 + workflow: marello_order_b2c_new_workflow_1 required: false placeholder: marello.pdf.config.fields.email_workflow_transition.placeholder @@ -144,6 +151,7 @@ system_configuration: children: - marello_pdf.localization - marello_pdf.logo + - marello_pdf.logo_width - marello_pdf.company_address - marello_pdf.company_email - marello_pdf.company_phone diff --git a/src/Marello/Bundle/PdfBundle/Resources/translations/messages.en.yml b/src/Marello/Bundle/PdfBundle/Resources/translations/messages.en.yml index 05916891c..5ca19599b 100644 --- a/src/Marello/Bundle/PdfBundle/Resources/translations/messages.en.yml +++ b/src/Marello/Bundle/PdfBundle/Resources/translations/messages.en.yml @@ -19,6 +19,9 @@ marello: logo: label: "Company logo" tooltip: "Upload a logo that will be displayed on top of your PDF document(image/jpeg, image/png, image/gif, image/svg)." + logo_width: + label: "Company logo width" + tooltip: "Enter logo width in pixels here." company_address: label: "Company address" tooltip: "Enter company address information here, including the company name and country." diff --git a/src/Marello/Bundle/PdfBundle/Resources/views/Download/util.html.twig b/src/Marello/Bundle/PdfBundle/Resources/views/Download/util.html.twig index ea8473d4e..646ec610c 100644 --- a/src/Marello/Bundle/PdfBundle/Resources/views/Download/util.html.twig +++ b/src/Marello/Bundle/PdfBundle/Resources/views/Download/util.html.twig @@ -2,7 +2,7 @@
diff --git a/src/Marello/Bundle/PricingBundle/EventListener/Datagrid/ChannelPricesDatagridListener.php b/src/Marello/Bundle/PricingBundle/EventListener/Datagrid/ChannelPricesDatagridListener.php index d3445f71b..03d1a3179 100644 --- a/src/Marello/Bundle/PricingBundle/EventListener/Datagrid/ChannelPricesDatagridListener.php +++ b/src/Marello/Bundle/PricingBundle/EventListener/Datagrid/ChannelPricesDatagridListener.php @@ -2,136 +2,38 @@ namespace Marello\Bundle\PricingBundle\EventListener\Datagrid; -use Doctrine\ORM\Query\Expr; -use Oro\Bundle\DataGridBundle\Datagrid\Common\DatagridConfiguration; +use Marello\Bundle\PricingBundle\Entity\AssembledChannelPriceList; +use Oro\Bundle\DataGridBundle\Datasource\ResultRecord; use Oro\Bundle\DataGridBundle\Event\BuildBefore; +use Oro\Bundle\DataGridBundle\Event\OrmResultAfter; +use Oro\Bundle\EntityBundle\ORM\DoctrineHelper; class ChannelPricesDatagridListener { - const DATA_NAME = 'channelPrices'; - const JOIN_ALIAS = 'cpr'; - const CHANNEL_DATA_NAME = 'channel'; - const CHANNEL_JOIN_ALIAS = 'ch'; - const DEFAULT_DATA_NAME = 'defaultPrice'; - const DEFAULT_JOIN_ALIAS = 'defcpr'; - const SPECIAL_DATA_NAME = 'specialPrice'; - const SPECIAL_JOIN_ALIAS = 'spcpr'; - - /** @var string */ - protected $relatedEntityClass; - - /** @var Expr */ - protected $expressionBuilder; - - /** - * @param string $relatedEntityClass - */ - public function __construct( - $relatedEntityClass - ) { - $this->relatedEntityClass = $relatedEntityClass; - - $this->expressionBuilder = new Expr(); - } - - /** - * @param BuildBefore $event - */ - public function onBuildBefore(BuildBefore $event) - { - $config = $event->getConfig(); - - $this->addSelect($config); - $this->addJoin($config); - $this->addColumn($config); - $this->addSorter($config); - $this->addFilter($config); - } - - /** - * @param DatagridConfiguration $configuration - * @return string - * @throws \InvalidArgumentException when a root entity not found in the grid - */ - protected function getAlias(DatagridConfiguration $configuration) - { - $rootAlias = $configuration->getOrmQuery()->getRootAlias(); - if (!$rootAlias) { - throw new \InvalidArgumentException( - sprintf( - 'A root entity is missing for grid "%s"', - $configuration->getName() - ) - ); - } - - return $rootAlias; - } - - /** - * @return string - */ - protected function getDataName() - { - return self::DATA_NAME; - } + const DEFAULT_PRICES_COLUMN = 'defaultChannelPrices'; + const SPECIAL_PRICES_COLUMN = 'specialChannelPrices'; /** - * @return string + * @var DoctrineHelper */ - protected function getJoinAlias() - { - return self::JOIN_ALIAS; - } + protected $doctrineHelper; /** - * @param DatagridConfiguration $config + * @param DoctrineHelper $doctrineHelper */ - protected function addSelect(DatagridConfiguration $config) + public function __construct(DoctrineHelper $doctrineHelper) { - $ormQuery = $config->getOrmQuery(); - $ormQuery - ->addSelect( - sprintf( - 'GROUP_CONCAT( - DISTINCT CONCAT_WS(\'|\', %1$s.name, %2$s.value, %2$s.currency) SEPARATOR \';\' - ) as defaultChannelPrices', - self::CHANNEL_JOIN_ALIAS, - self::DEFAULT_JOIN_ALIAS - ) - ) - ->addSelect( - sprintf( - 'GROUP_CONCAT( - DISTINCT CONCAT_WS(\'|\', %1$s.name, %2$s.value, %2$s.currency) SEPARATOR \';\' - ) as specialChannelPrices', - self::CHANNEL_JOIN_ALIAS, - self::SPECIAL_JOIN_ALIAS - ) - ) - ->addSelect(sprintf('sum(%s.value) as defaultChannelPricesSum', self::DEFAULT_JOIN_ALIAS)) - ->addSelect(sprintf('sum(%s.value) as specialChannelPricesSum', self::SPECIAL_JOIN_ALIAS)); + $this->doctrineHelper = $doctrineHelper; } /** - * @param DatagridConfiguration $config + * @param BuildBefore $event */ - protected function addJoin(DatagridConfiguration $config) + public function onBuildBefore(BuildBefore $event) { - $ormQuery = $config->getOrmQuery(); - $ormQuery - ->addLeftJoin(sprintf('%s.%s', $this->getAlias($config), self::DATA_NAME), $this->getJoinAlias()) - ->addLeftJoin(sprintf('%s.%s', $this->getJoinAlias(), self::CHANNEL_DATA_NAME), self::CHANNEL_JOIN_ALIAS) - ->addLeftJoin(sprintf('%s.%s', $this->getJoinAlias(), self::DEFAULT_DATA_NAME), self::DEFAULT_JOIN_ALIAS) - ->addLeftJoin(sprintf('%s.%s', $this->getJoinAlias(), self::SPECIAL_DATA_NAME), self::SPECIAL_JOIN_ALIAS); - } + $config = $event->getConfig(); - /** - * @param DatagridConfiguration $config - */ - protected function addColumn(DatagridConfiguration $config) - { - $config->offsetSetByPath(sprintf('[columns][%s]', 'defaultChannelPrices'), [ + $config->offsetSetByPath(sprintf('[columns][%s]', self::DEFAULT_PRICES_COLUMN), [ 'label' => 'marello.pricing.assembledchannelpricelist.default_price.plural_label', 'type' => 'twig', 'frontend_type' => 'html', @@ -139,7 +41,7 @@ protected function addColumn(DatagridConfiguration $config) 'renderable' => false, 'align' => 'right' ]); - $config->offsetSetByPath(sprintf('[columns][%s]', 'specialChannelPrices'), [ + $config->offsetSetByPath(sprintf('[columns][%s]', self::SPECIAL_PRICES_COLUMN), [ 'label' => 'marello.pricing.assembledchannelpricelist.special_price.plural_label', 'type' => 'twig', 'frontend_type' => 'html', @@ -150,41 +52,68 @@ protected function addColumn(DatagridConfiguration $config) } /** - * @param DatagridConfiguration $config + * @param OrmResultAfter $event */ - protected function addSorter(DatagridConfiguration $config) + public function onResultAfter(OrmResultAfter $event) { - $config - ->offsetSetByPath( - sprintf('[sorters][columns][%s]', 'defaultChannelPrices'), - ['data_name' => 'defaultChannelPricesSum'] - ) - ->offsetSetByPath( - sprintf('[sorters][columns][%s]', 'specialChannelPrices'), - ['data_name' => 'specialChannelPricesSum'] - ); + /** @var ResultRecord[] $records */ + $records = $event->getRecords(); + + $productIds = array_map( + function (ResultRecord $record) { + return $record->getValue('id'); + }, + $records + ); + + $this->addProductPrices($productIds, $records); } /** - * @param DatagridConfiguration $config + * @param array $productIds + * @param array|ResultRecord[] $records */ - protected function addFilter(DatagridConfiguration $config) + protected function addProductPrices(array $productIds, array $records) { - $config->offsetSetByPath( - sprintf('[filters][columns][%s]', 'defaultChannelPrices'), - [ - 'type' => 'number', - 'data_name' => self::DEFAULT_JOIN_ALIAS . '.value', - 'enabled' => false, - ] - ); - $config->offsetSetByPath( - sprintf('[filters][columns][%s]', 'specialChannelPrices'), - [ - 'type' => 'number', - 'data_name' => self::SPECIAL_JOIN_ALIAS . '.value', - 'enabled' => false, - ] - ); + $groupedPrices = $this->getPrices($productIds); + + foreach ($records as $record) { + $priceLists = []; + $productId = $record->getValue('id'); + + if (array_key_exists($productId, $groupedPrices)) { + /** @var AssembledChannelPriceList[] $priceLists */ + $priceLists = $groupedPrices[$productId]; + } + $data = []; + foreach ($priceLists as $priceList) { + if ($priceList->getDefaultPrice()) { + $data[self::DEFAULT_PRICES_COLUMN][] = $priceList->getDefaultPrice(); + } + if ($priceList->getSpecialPrice()) { + $data[self::SPECIAL_PRICES_COLUMN][] = $priceList->getSpecialPrice(); + } + } + + $record->addData($data); + } + } + + /** + * @param array $productIds + * @return array + */ + protected function getPrices(array $productIds) + { + $prices = $this->doctrineHelper + ->getEntityRepository(AssembledChannelPriceList::class) + ->findBy(['product' => $productIds]); + + $result = []; + foreach ($prices as $price) { + $result[$price->getProduct()->getId()][] = $price; + } + + return $result; } } diff --git a/src/Marello/Bundle/PricingBundle/EventListener/Datagrid/PricesDatagridListener.php b/src/Marello/Bundle/PricingBundle/EventListener/Datagrid/PricesDatagridListener.php index 0a0fa4b17..176db9b8f 100644 --- a/src/Marello/Bundle/PricingBundle/EventListener/Datagrid/PricesDatagridListener.php +++ b/src/Marello/Bundle/PricingBundle/EventListener/Datagrid/PricesDatagridListener.php @@ -2,143 +2,39 @@ namespace Marello\Bundle\PricingBundle\EventListener\Datagrid; -use Doctrine\ORM\Query\Expr; -use Oro\Bundle\DataGridBundle\Datagrid\Common\DatagridConfiguration; +use Marello\Bundle\PricingBundle\Entity\AssembledPriceList; +use Oro\Bundle\DataGridBundle\Datasource\ResultRecord; use Oro\Bundle\DataGridBundle\Event\BuildBefore; +use Oro\Bundle\DataGridBundle\Event\OrmResultAfter; +use Oro\Bundle\EntityBundle\ORM\DoctrineHelper; class PricesDatagridListener { - const DATA_NAME = 'prices'; - const JOIN_ALIAS = 'pr'; - const DEFAULT_DATA_NAME = 'defaultPrice'; - const DEFAULT_JOIN_ALIAS = 'defpr'; - const SPECIAL_DATA_NAME = 'specialPrice'; - const SPECIAL_JOIN_ALIAS = 'sppr'; - const MSRP_DATA_NAME = 'msrpPrice'; - const MSRP_JOIN_ALIAS = 'mspr'; - - /** @var string */ - protected $relatedEntityClass; - - /** @var Expr */ - protected $expressionBuilder; - - /** - * @param string $relatedEntityClass - */ - public function __construct( - $relatedEntityClass - ) { - $this->relatedEntityClass = $relatedEntityClass; - - $this->expressionBuilder = new Expr(); - } - - /** - * @param BuildBefore $event - */ - public function onBuildBefore(BuildBefore $event) - { - $config = $event->getConfig(); - - $this->addSelect($config); - $this->addJoin($config); - $this->addColumn($config); - $this->addSorter($config); - $this->addFilter($config); - } + const DEFAULT_PRICES_COLUMN = 'defaultPrices'; + const SPECIAL_PRICES_COLUMN = 'specialPrices'; + const MSRP_PRICES_COLUMN = 'msrpPrices'; /** - * @param DatagridConfiguration $configuration - * @return string - * @throws \InvalidArgumentException when a root entity not found in the grid + * @var DoctrineHelper */ - protected function getAlias(DatagridConfiguration $configuration) - { - $rootAlias = $configuration->getOrmQuery()->getRootAlias(); - if (!$rootAlias) { - throw new \InvalidArgumentException( - sprintf( - 'A root entity is missing for grid "%s"', - $configuration->getName() - ) - ); - } - - return $rootAlias; - } + protected $doctrineHelper; /** - * @return string + * @param DoctrineHelper $doctrineHelper */ - protected function getDataName() + public function __construct(DoctrineHelper $doctrineHelper) { - return self::DATA_NAME; + $this->doctrineHelper = $doctrineHelper; } /** - * @return string - */ - protected function getJoinAlias() - { - return self::JOIN_ALIAS; - } - - /** - * @param DatagridConfiguration $config - */ - protected function addSelect(DatagridConfiguration $config) - { - $ormQuery = $config->getOrmQuery(); - $ormQuery - ->addSelect( - sprintf( - 'GROUP_CONCAT( - DISTINCT CONCAT_WS(\'|\', %1$s.value, %1$s.currency) SEPARATOR \';\' - ) as defaultPrices', - self::DEFAULT_JOIN_ALIAS - ) - ) - ->addSelect( - sprintf( - 'GROUP_CONCAT( - DISTINCT CONCAT_WS(\'|\', %1$s.value, %1$s.currency) SEPARATOR \';\' - ) as specialPrices', - self::SPECIAL_JOIN_ALIAS - ) - ) - ->addSelect( - sprintf( - 'GROUP_CONCAT( - DISTINCT CONCAT_WS(\'|\', %1$s.value, %1$s.currency) SEPARATOR \';\' - ) as msrpPrices', - self::MSRP_JOIN_ALIAS - ) - ) - ->addSelect(sprintf('SUM(%s.value) as defaultPricesSum', self::DEFAULT_JOIN_ALIAS)) - ->addSelect(sprintf('SUM(%s.value) as specialPricesSum', self::SPECIAL_JOIN_ALIAS)) - ->addSelect(sprintf('SUM(%s.value) as msrpPricesSum', self::MSRP_JOIN_ALIAS)); - } - - /** - * @param DatagridConfiguration $config + * @param BuildBefore $event */ - protected function addJoin(DatagridConfiguration $config) + public function onBuildBefore(BuildBefore $event) { - $ormQuery = $config->getOrmQuery(); - $ormQuery - ->addLeftJoin(sprintf('%s.%s', $this->getAlias($config), self::DATA_NAME), $this->getJoinAlias()) - ->addLeftJoin(sprintf('%s.%s', $this->getJoinAlias(), self::DEFAULT_DATA_NAME), self::DEFAULT_JOIN_ALIAS) - ->addLeftJoin(sprintf('%s.%s', $this->getJoinAlias(), self::SPECIAL_DATA_NAME), self::SPECIAL_JOIN_ALIAS) - ->addLeftJoin(sprintf('%s.%s', $this->getJoinAlias(), self::MSRP_DATA_NAME), self::MSRP_JOIN_ALIAS); - } + $config = $event->getConfig(); - /** - * @param DatagridConfiguration $config - */ - protected function addColumn(DatagridConfiguration $config) - { - $config->offsetSetByPath(sprintf('[columns][%s]', 'defaultPrices'), [ + $config->offsetSetByPath(sprintf('[columns][%s]', self::DEFAULT_PRICES_COLUMN), [ 'label' => 'marello.pricing.assembledpricelist.default_price.plural_label', 'type' => 'twig', 'frontend_type' => 'html', @@ -146,7 +42,7 @@ protected function addColumn(DatagridConfiguration $config) 'renderable' => false, 'align' => 'right' ]); - $config->offsetSetByPath(sprintf('[columns][%s]', 'specialPrices'), [ + $config->offsetSetByPath(sprintf('[columns][%s]', self::SPECIAL_PRICES_COLUMN), [ 'label' => 'marello.pricing.assembledpricelist.special_price.plural_label', 'type' => 'twig', 'frontend_type' => 'html', @@ -154,7 +50,7 @@ protected function addColumn(DatagridConfiguration $config) 'renderable' => false, 'align' => 'right' ]); - $config->offsetSetByPath(sprintf('[columns][%s]', 'msrpPrices'), [ + $config->offsetSetByPath(sprintf('[columns][%s]', self::MSRP_PRICES_COLUMN), [ 'label' => 'marello.pricing.assembledpricelist.msrp_price.plural_label', 'type' => 'twig', 'frontend_type' => 'html', @@ -165,44 +61,71 @@ protected function addColumn(DatagridConfiguration $config) } /** - * @param DatagridConfiguration $config + * @param OrmResultAfter $event */ - protected function addSorter(DatagridConfiguration $config) + public function onResultAfter(OrmResultAfter $event) { - $config - ->offsetSetByPath(sprintf('[sorters][columns][%s]', 'defaultPrices'), ['data_name' => 'defaultPricesSum']) - ->offsetSetByPath(sprintf('[sorters][columns][%s]', 'specialPrices'), ['data_name' => 'specialPricesSum']) - ->offsetSetByPath(sprintf('[sorters][columns][%s]', 'msrpPrices'), ['data_name' => 'msrpPricesSum']); + /** @var ResultRecord[] $records */ + $records = $event->getRecords(); + + $productIds = array_map( + function (ResultRecord $record) { + return $record->getValue('id'); + }, + $records + ); + + $this->addProductPrices($productIds, $records); } /** - * @param DatagridConfiguration $config + * @param array $productIds + * @param array|ResultRecord[] $records */ - protected function addFilter(DatagridConfiguration $config) + protected function addProductPrices(array $productIds, array $records) { - $config->offsetSetByPath( - sprintf('[filters][columns][%s]', 'defaultPrices'), - [ - 'type' => 'number', - 'data_name' => self::DEFAULT_JOIN_ALIAS . '.value', - 'enabled' => false, - ] - ); - $config->offsetSetByPath( - sprintf('[filters][columns][%s]', 'specialPrices'), - [ - 'type' => 'number', - 'data_name' => self::SPECIAL_JOIN_ALIAS . '.value', - 'enabled' => false, - ] - ); - $config->offsetSetByPath( - sprintf('[filters][columns][%s]', 'msrpPrices'), - [ - 'type' => 'number', - 'data_name' => self::MSRP_JOIN_ALIAS . '.value', - 'enabled' => false, - ] - ); + $groupedPrices = $this->getPrices($productIds); + + foreach ($records as $record) { + $priceLists = []; + $productId = $record->getValue('id'); + + if (array_key_exists($productId, $groupedPrices)) { + /** @var AssembledPriceList[] $priceLists */ + $priceLists = $groupedPrices[$productId]; + } + $data = []; + foreach ($priceLists as $priceList) { + if ($priceList->getDefaultPrice()) { + $data[self::DEFAULT_PRICES_COLUMN][] = $priceList->getDefaultPrice(); + } + if ($priceList->getSpecialPrice()) { + $data[self::SPECIAL_PRICES_COLUMN][] = $priceList->getSpecialPrice(); + } + if ($priceList->getMsrpPrice()) { + $data[self::MSRP_PRICES_COLUMN][] = $priceList->getMsrpPrice(); + } + } + + $record->addData($data); + } + } + + /** + * @param array $productIds + * @return array + */ + protected function getPrices(array $productIds) + { + $prices = $this->doctrineHelper + ->getEntityRepository(AssembledPriceList::class) + ->findBy(['product' => $productIds]); + + $result = []; + foreach ($prices as $price) { + $result[$price->getProduct()->getId()][] = $price; + } + + return $result; } } diff --git a/src/Marello/Bundle/PricingBundle/Resources/config/services.yml b/src/Marello/Bundle/PricingBundle/Resources/config/services.yml index 3fd6760df..6bfed6d6e 100644 --- a/src/Marello/Bundle/PricingBundle/Resources/config/services.yml +++ b/src/Marello/Bundle/PricingBundle/Resources/config/services.yml @@ -69,13 +69,15 @@ services: marello_productprice.pricing.listener.datagrid.products_grid.prices: class: 'Marello\Bundle\PricingBundle\EventListener\Datagrid\PricesDatagridListener' arguments: - - 'Marello\Bundle\ProductBundle\Entity\Product' + - '@oro_entity.doctrine_helper' tags: - { name: kernel.event_listener, event: oro_datagrid.datagrid.build.before.marello-products-grid, method: onBuildBefore } + - { name: kernel.event_listener, event: oro_datagrid.orm_datasource.result.after.marello-products-grid, method: onResultAfter } marello_productprice.pricing.listener.datagrid.products_grid.channel_prices: class: 'Marello\Bundle\PricingBundle\EventListener\Datagrid\ChannelPricesDatagridListener' arguments: - - 'Marello\Bundle\ProductBundle\Entity\Product' + - '@oro_entity.doctrine_helper' tags: - - { name: kernel.event_listener, event: oro_datagrid.datagrid.build.before.marello-products-grid, method: onBuildBefore } \ No newline at end of file + - { name: kernel.event_listener, event: oro_datagrid.datagrid.build.before.marello-products-grid, method: onBuildBefore } + - { name: kernel.event_listener, event: oro_datagrid.orm_datasource.result.after.marello-products-grid, method: onResultAfter } \ No newline at end of file diff --git a/src/Marello/Bundle/PricingBundle/Resources/views/Datagrid/Property/defaultChannelPrices.html.twig b/src/Marello/Bundle/PricingBundle/Resources/views/Datagrid/Property/defaultChannelPrices.html.twig index 63a2d5436..3875a5c33 100644 --- a/src/Marello/Bundle/PricingBundle/Resources/views/Datagrid/Property/defaultChannelPrices.html.twig +++ b/src/Marello/Bundle/PricingBundle/Resources/views/Datagrid/Property/defaultChannelPrices.html.twig @@ -1,7 +1,4 @@ -{% set prices = record.getValue('defaultChannelPrices')|split(';') %} -{% for index, valueSet in prices %} - {% set values = valueSet|split('|') %} - {% if values|length == 3 %} - {{ values[0] }}: {{ values[1]|oro_format_currency({'currency': values[2]}) }}
- {% endif %} +{% set prices = record.getValue('defaultChannelPrices') %} +{% for index, price in prices %} + {{ price.channel.name ~ ': ' ~ price.value|oro_format_currency({'currency': price.currency}) }}
{% endfor %} diff --git a/src/Marello/Bundle/PricingBundle/Resources/views/Datagrid/Property/defaultPrices.html.twig b/src/Marello/Bundle/PricingBundle/Resources/views/Datagrid/Property/defaultPrices.html.twig index cac4859ba..bf7a5312e 100644 --- a/src/Marello/Bundle/PricingBundle/Resources/views/Datagrid/Property/defaultPrices.html.twig +++ b/src/Marello/Bundle/PricingBundle/Resources/views/Datagrid/Property/defaultPrices.html.twig @@ -1,7 +1,4 @@ -{% set prices = record.getValue('defaultPrices')|split(';') %} -{% for index, valueSet in prices %} - {% set values = valueSet|split('|') %} - {% if values|length == 2 %} - {{ values[0]|oro_format_currency({'currency': values[1]}) }}
- {% endif %} +{% set prices = record.getValue('defaultPrices') %} +{% for index, price in prices %} + {{ price.value|oro_format_currency({'currency': price.currency}) }}
{% endfor %} \ No newline at end of file diff --git a/src/Marello/Bundle/PricingBundle/Resources/views/Datagrid/Property/msrpPrices.html.twig b/src/Marello/Bundle/PricingBundle/Resources/views/Datagrid/Property/msrpPrices.html.twig index c2bd44916..ed6ace409 100644 --- a/src/Marello/Bundle/PricingBundle/Resources/views/Datagrid/Property/msrpPrices.html.twig +++ b/src/Marello/Bundle/PricingBundle/Resources/views/Datagrid/Property/msrpPrices.html.twig @@ -1,7 +1,4 @@ -{% set prices = record.getValue('msrpPrices')|split(';') %} -{% for index, valueSet in prices %} - {% set values = valueSet|split('|') %} - {% if values|length == 2 %} - {{ values[0]|oro_format_currency({'currency': values[1]}) }}
- {% endif %} +{% set prices = record.getValue('msrpPrices') %} +{% for index, price in prices %} + {{ price.value|oro_format_currency({'currency': price.currency}) }}
{% endfor %} \ No newline at end of file diff --git a/src/Marello/Bundle/PricingBundle/Resources/views/Datagrid/Property/specialChannelPrices.html.twig b/src/Marello/Bundle/PricingBundle/Resources/views/Datagrid/Property/specialChannelPrices.html.twig index b625f13de..2fe08e90a 100644 --- a/src/Marello/Bundle/PricingBundle/Resources/views/Datagrid/Property/specialChannelPrices.html.twig +++ b/src/Marello/Bundle/PricingBundle/Resources/views/Datagrid/Property/specialChannelPrices.html.twig @@ -1,7 +1,4 @@ -{% set prices = record.getValue('specialChannelPrices')|split(';') %} -{% for index, valueSet in prices %} - {% set values = valueSet|split('|') %} - {% if values|length == 3 %} - {{ values[0] }}: {{ values[1]|oro_format_currency({'currency': values[2]}) }}
- {% endif %} +{% set prices = record.getValue('specialChannelPrices') %} +{% for index, price in prices %} + {{ price.channel.name ~ ': ' ~ price.value|oro_format_currency({'currency': price.currency}) }}
{% endfor %} \ No newline at end of file diff --git a/src/Marello/Bundle/PricingBundle/Resources/views/Datagrid/Property/specialPrices.html.twig b/src/Marello/Bundle/PricingBundle/Resources/views/Datagrid/Property/specialPrices.html.twig index 7791957fb..dea509bf7 100644 --- a/src/Marello/Bundle/PricingBundle/Resources/views/Datagrid/Property/specialPrices.html.twig +++ b/src/Marello/Bundle/PricingBundle/Resources/views/Datagrid/Property/specialPrices.html.twig @@ -1,7 +1,4 @@ -{% set prices = record.getValue('specialPrices')|split(';') %} -{% for index, valueSet in prices %} - {% set values = valueSet|split('|') %} - {% if values|length == 2 %} - {{ values[0]|oro_format_currency({'currency': values[1]}) }}
- {% endif %} +{% set prices = record.getValue('specialPrices') %} +{% for index, price in prices %} + {{ price.value|oro_format_currency({'currency': price.currency}) }}
{% endfor %} \ No newline at end of file diff --git a/src/Marello/Bundle/PricingBundle/Tests/Functional/Api/AssembledChannelPriceListJsonApiTest.php b/src/Marello/Bundle/PricingBundle/Tests/Functional/Api/AssembledChannelPriceListJsonApiTest.php index 049a05343..5553ab726 100644 --- a/src/Marello/Bundle/PricingBundle/Tests/Functional/Api/AssembledChannelPriceListJsonApiTest.php +++ b/src/Marello/Bundle/PricingBundle/Tests/Functional/Api/AssembledChannelPriceListJsonApiTest.php @@ -11,7 +11,10 @@ use Marello\Bundle\SalesBundle\Tests\Functional\DataFixtures\LoadSalesData; use Marello\Bundle\ProductBundle\Tests\Functional\DataFixtures\LoadProductData; use Marello\Bundle\PricingBundle\Tests\Functional\DataFixtures\LoadProductChannelPricingData; - +/** + * @dbIsolationPerTest + * @nestTransactionsWithSavepoints + */ class AssembledChannelPriceListJsonApiTest extends RestJsonApiTestCase { const TESTING_ENTITY = 'marelloassembledchannelpricelists'; diff --git a/src/Marello/Bundle/ProductBundle/Controller/ProductController.php b/src/Marello/Bundle/ProductBundle/Controller/ProductController.php index dc70dc63c..c43412f3f 100644 --- a/src/Marello/Bundle/ProductBundle/Controller/ProductController.php +++ b/src/Marello/Bundle/ProductBundle/Controller/ProductController.php @@ -59,22 +59,25 @@ public function createAction(Request $request) */ protected function createStepOne(Request $request) { - $form = $this->createForm(ProductStepOneType::class); + $form = $this->createForm(ProductStepOneType::class, new Product()); $handler = new ProductCreateStepOneHandler($form, $request); - $productTypesProvider = $this->get('marello_product.provider.product_types'); - $em = $this->get('doctrine.orm.entity_manager'); - /** @var AttributeFamily $attributeFamily */ - $attributeFamilies = $em - ->getRepository(AttributeFamily::class) - ->findBy(['entityClass' => Product::class]); + $queryParams = $request->query->all(); + if ($handler->process()) { - return $this->forward('MarelloProductBundle:Product:createStepTwo'); + return $this->forward('MarelloProductBundle:Product:createStepTwo', [], $queryParams); } - if (count($productTypesProvider->getProductTypes()) <= 1 && count($attributeFamilies) <= 1) { + + $productTypesProvider = $this->get('marello_product.provider.product_types'); + $em = $this->get('oro_entity.doctrine_helper'); + /** @var AttributeFamily $attributeFamily */ + $countAttributeFamilies = $em + ->getEntityRepositoryForClass(AttributeFamily::class) + ->countFamiliesByEntityClass(Product::class); + if (count($productTypesProvider->getProductTypes()) <= 1 && $countAttributeFamilies <= 1) { $request->setMethod('POST'); $request->request->set('input_action', 'marello_product_create'); $request->request->set('single_product_type', true); - return $this->forward('MarelloProductBundle:Product:createStepTwo'); + return $this->forward('MarelloProductBundle:Product:createStepTwo', [], $queryParams); } return [ @@ -109,27 +112,34 @@ public function createStepTwoAction(Request $request) protected function createStepTwo(Request $request, Product $product) { if ($request->get('input_action') === 'marello_product_create') { - $formStepOne = $this->createForm(ProductStepOneType::class, $product); - $em = $this->get('doctrine.orm.entity_manager'); + $form = $this->createForm(ProductStepOneType::class, $product); + $queryParams = $request->query->all(); + $form->handleRequest($request); + $formData = $form->all(); + if ($request->get('single_product_type')) { - $type = Product::DEFAULT_PRODUCT_TYPE; + $em = $this->get('oro_entity.doctrine_helper'); + /** @var AttributeFamily $attributeFamily */ $attributeFamily = $em - ->getRepository(AttributeFamily::class) + ->getEntityRepositoryForClass(AttributeFamily::class) ->findOneBy(['entityClass' => Product::class]); - } else { - $formStepOne->handleRequest($request); - $type = $formStepOne->get('type')->getData(); - $attributeFamily = $formStepOne->get('attributeFamily')->getData(); + $product->setType(Product::DEFAULT_PRODUCT_TYPE); + $product->setAttributeFamily($attributeFamily); } - $product->setType($type); - $product->setAttributeFamily($attributeFamily); - $form = $this->createForm(ProductType::class, $product); + if (!empty($formData)) { + $form = $this->createForm(ProductType::class, $product); + foreach ($formData as $key => $item) { + $data = $item->getData(); + $form->get($key)->setData($data); + } + } return [ 'form' => $form->createView(), 'entity' => $product, - 'isWidgetContext' => (bool)$request->get('_wid', false) + 'isWidgetContext' => (bool)$request->get('_wid', false), + 'queryParams' => $queryParams ]; } diff --git a/src/Marello/Bundle/ProductBundle/Entity/Builder/ProductFamilyBuilder.php b/src/Marello/Bundle/ProductBundle/Entity/Builder/ProductFamilyBuilder.php new file mode 100644 index 000000000..842694727 --- /dev/null +++ b/src/Marello/Bundle/ProductBundle/Entity/Builder/ProductFamilyBuilder.php @@ -0,0 +1,107 @@ + 'General', + 'groupCode' => 'general', + 'attributes' => [ + 'sku', + 'names', + 'channels', + 'status', + 'prices', + 'channelPrices', + 'taxCode', + 'salesChannelTaxCodes', + 'weight', + 'manufacturingCode', + 'warranty', + 'suppliers', + 'categories', + 'image', + ], + 'groupVisibility' => true, + ] + ]; + + /** @var TranslatorInterface */ + private $translator; + + /** @var AttributeGroupManager */ + private $attributeGroupManager; + + /** @var AttributeFamily */ + private $family; + + /** + * @param TranslatorInterface $translator + * @param AttributeGroupManager $attributeGroupManager + */ + public function __construct(TranslatorInterface $translator, AttributeGroupManager $attributeGroupManager) + { + $this->translator = $translator; + $this->attributeGroupManager = $attributeGroupManager; + } + + /** + * @param Organization $organization + * @return $this + */ + public function createDefaultFamily(Organization $organization) + { + $this->family = new AttributeFamily(); + $this->family->setCode(self::DEFAULT_FAMILY_CODE); + $this->family->setEntityClass(Product::class); + $this->family->setOwner($organization); + $this->family->setDefaultLabel( + $this->translator->trans('oro.entityconfig.attribute.entity.attributefamily.default.label') + ); + + return $this; + } + + /** + * @return $this + */ + public function addDefaultAttributeGroups() + { + if (!$this->family instanceof AttributeFamily) { + throw new \LogicException( + sprintf('Attribute groups can only be added to an instance of %s.', AttributeFamily::class) + ); + } + $attributeGroups = $this->attributeGroupManager->createGroupsWithAttributes( + Product::class, + self::$groups + ); + foreach ($attributeGroups as $attributeGroup) { + $this->family->addAttributeGroup($attributeGroup); + } + + return $this; + } + + /** + * @return AttributeFamily|null + */ + public function getFamily(): ?AttributeFamily + { + return $this->family; + } +} diff --git a/src/Marello/Bundle/ProductBundle/Entity/Product.php b/src/Marello/Bundle/ProductBundle/Entity/Product.php index 835ec31a3..cb1c63408 100644 --- a/src/Marello/Bundle/ProductBundle/Entity/Product.php +++ b/src/Marello/Bundle/ProductBundle/Entity/Product.php @@ -35,8 +35,8 @@ * }, * uniqueConstraints={ * @ORM\UniqueConstraint( - * name="marello_product_product_skuidx", - * columns={"sku"} + * name="marello_product_product_skuorgidx", + * columns={"sku","organization_id"} * ) * } * ) @@ -362,9 +362,9 @@ class Product extends ExtendProduct implements /** * @var ArrayCollection - * unidirectional many-to-many * @ORM\ManyToMany(targetEntity="Marello\Bundle\SalesBundle\Entity\SalesChannel", - * fetch="EAGER" + * inversedBy="products", + * fetch="EAGER" * ) * @ORM\JoinTable(name="marello_product_saleschannel") * @Oro\ConfigField( @@ -386,6 +386,23 @@ class Product extends ExtendProduct implements */ protected $channels; + /** + * @var string + * + * @ORM\Column(name="channels_codes", type="text", nullable=true) + * @Oro\ConfigField( + * defaultValues={ + * "dataaudit"={ + * "auditable"=true + * }, + * "importexport"={ + * "excluded"=true + * } + * } + * ) + */ + protected $channelsCodes; + /** * @var Variant * @@ -546,7 +563,7 @@ class Product extends ExtendProduct implements /** * @var ArrayCollection|Category[] * - * @ORM\ManyToMany(targetEntity="Marello\Bundle\CatalogBundle\Entity\Category", mappedBy="products") + * @ORM\ManyToMany(targetEntity="Marello\Bundle\CatalogBundle\Entity\Category", mappedBy="products", fetch="EAGER") * @Oro\ConfigField( * defaultValues={ * "dataaudit"={ @@ -566,6 +583,23 @@ class Product extends ExtendProduct implements */ protected $categories; + /** + * @var string + * + * @ORM\Column(name="categories_codes", type="text", nullable=true) + * @Oro\ConfigField( + * defaultValues={ + * "dataaudit"={ + * "auditable"=true + * }, + * "importexport"={ + * "excluded"=true + * } + * } + * ) + */ + protected $categoriesCodes; + /** * @var AttributeFamily * @@ -916,6 +950,33 @@ public function addChannel(SalesChannel $channel) { if (!$this->channels->contains($channel)) { $this->channels->add($channel); + $this->addChannelCode($channel->getCode()); + } + + return $this; + } + + /** + * @param string $code + * @return $this + */ + public function addChannelCode($code) + { + if (strpos($this->channelsCodes, '|') === false) { + $channelsCodes = []; + } else { + $channelsCodes = $this->channelsCodes; + if (substr($channelsCodes, 0, 1) === '|') { + $channelsCodes = substr($channelsCodes, 1); + } + if (substr($channelsCodes, -1, 1) === '|') { + $channelsCodes = substr($channelsCodes, 0, -1); + } + $channelsCodes = explode("|", $channelsCodes); + } + if (!in_array($code, $channelsCodes)) { + $channelsCodes[] = $code; + $this->channelsCodes = sprintf('|%s|', implode('|', $channelsCodes)); } return $this; @@ -949,6 +1010,16 @@ public function removeChannel(SalesChannel $channel) { if ($this->channels->contains($channel)) { $this->channels->removeElement($channel); + $channelsCodes = $this->channelsCodes; + if (substr($channelsCodes, 0, 1) === '|') { + $channelsCodes = substr($channelsCodes, 1); + } + if (substr($channelsCodes, -1, 1) === '|') { + $channelsCodes = substr($channelsCodes, 0, -1); + } + $channelsCodes = explode("|", $channelsCodes); + $channelsCodes = array_diff([$channelsCodes], [$channel->getCode()]); + $this->channelsCodes = sprintf('|%s|', implode('|', $channelsCodes)); } return $this; @@ -1280,7 +1351,36 @@ public function addCategory(Category $category) { if (!$this->hasCategory($category)) { $this->categories->add($category); - $category->addProduct($this); + if (!$category->hasProduct($this)) { + $category->addProduct($this); + } + $this->addCategoryCode($category->getCode()); + } + + return $this; + } + + /** + * @param string $code + * @return $this + */ + public function addCategoryCode($code) + { + if (strpos($this->categoriesCodes, '|') === false) { + $categoriesCodes = []; + } else { + $categoriesCodes = $this->categoriesCodes; + if (substr($categoriesCodes, 0, 1) === '|') { + $categoriesCodes = substr($categoriesCodes, 1); + } + if (substr($categoriesCodes, -1, 1) === '|') { + $categoriesCodes = substr($categoriesCodes, 0, -1); + } + $categoriesCodes = explode("|", $categoriesCodes); + } + if (!in_array($code, $categoriesCodes)) { + $categoriesCodes[] = $code; + $this->categoriesCodes = sprintf('|%s|', implode('|', $categoriesCodes)); } return $this; @@ -1295,10 +1395,21 @@ public function removeCategory(Category $category) if ($this->hasCategory($category)) { $this->categories->removeElement($category); $category->removeProduct($this); + $categoriesCodes = $this->categoriesCodes; + if (substr($categoriesCodes, 0, 1) === '|') { + $categoriesCodes = substr($categoriesCodes, 1); + } + if (substr($categoriesCodes, -1, 1) === '|') { + $categoriesCodes = substr($categoriesCodes, 0, -1); + } + $categoriesCodes = explode("|", $categoriesCodes); + $categoriesCodes = array_diff([$categoriesCodes], [$category->getCode()]); + $this->categoriesCodes = sprintf('|%s|', implode('|', $categoriesCodes)); } return $this; } + /** * @param Category $category diff --git a/src/Marello/Bundle/ProductBundle/Entity/Repository/ProductRepository.php b/src/Marello/Bundle/ProductBundle/Entity/Repository/ProductRepository.php index fdcf6b0e2..1d1b7ecff 100644 --- a/src/Marello/Bundle/ProductBundle/Entity/Repository/ProductRepository.php +++ b/src/Marello/Bundle/ProductBundle/Entity/Repository/ProductRepository.php @@ -6,6 +6,7 @@ use Marello\Bundle\ProductBundle\Entity\Product; use Marello\Bundle\SalesBundle\Entity\SalesChannel; +use Oro\Bundle\OrganizationBundle\Entity\Organization; use Oro\Bundle\SecurityBundle\ORM\Walker\AclHelper; class ProductRepository extends EntityRepository @@ -133,17 +134,24 @@ public function findBySalesChannel($salesChannel, array $productIds) } /** - * @param string $sku - * - * @return null|Product + * @param $sku + * @param Organization|null $organization + * @return int|mixed|string|null + * @throws \Doctrine\ORM\NonUniqueResultException */ - public function findOneBySku($sku) + public function findOneBySku($sku, Organization $organization = null) { $queryBuilder = $this->createQueryBuilder('product'); $queryBuilder->andWhere('UPPER(product.sku) = :sku') ->setParameter('sku', strtoupper($sku)); + if ($organization) { + $queryBuilder + ->andWhere('product.organization = :organization') + ->setParameter('organization', $organization); + } + return $this->aclHelper->apply($queryBuilder->getQuery())->getOneOrNullResult(); } @@ -200,8 +208,8 @@ public function getPurchaseOrderItemsCandidates() ->select( 'sup.name AS supplier, p.sku, - (i.desiredInventory - COALESCE(SUM(l.inventory - l.allocatedInventory), 0)) AS orderAmount, - i.purchaseInventory' + SUM(i.desiredInventory - COALESCE((l.inventory - l.allocatedInventory), 0)) AS orderAmount, + SUM(i.purchaseInventory) AS purchaseInventory' ) ->innerJoin('p.preferredSupplier', 'sup') ->innerJoin('p.status', 's') @@ -210,7 +218,7 @@ public function getPurchaseOrderItemsCandidates() ->where("sup.name <> ''") ->andWhere("s.name = 'enabled'") ->andWhere("i.replenishment = 'never_out_of_stock'") - ->groupBy('p.sku, sup.name, i.desiredInventory, i.purchaseInventory') + ->groupBy('sup.name, p.sku, i.desiredInventory, i.purchaseInventory') ->having('SUM(l.inventory - l.allocatedInventory) < i.purchaseInventory'); return $this->aclHelper->apply($qb->getQuery())->getResult(); diff --git a/src/Marello/Bundle/ProductBundle/EventListener/Datagrid/AbstractProductsGridListener.php b/src/Marello/Bundle/ProductBundle/EventListener/Datagrid/AbstractProductsGridListener.php new file mode 100644 index 000000000..cff24ada7 --- /dev/null +++ b/src/Marello/Bundle/ProductBundle/EventListener/Datagrid/AbstractProductsGridListener.php @@ -0,0 +1,55 @@ +doctrineHelper = $doctrineHelper; + } + + /** + * @param OrmResultAfter $event + */ + public function onResultAfter(OrmResultAfter $event) + { + /** @var ResultRecord[] $records */ + $records = $event->getRecords(); + $firstRecord = $records[0]; + if (!$firstRecord->getValue('product')) { + $productIds = array_map( + function (ResultRecord $record) { + return $record->getValue('id'); + }, + $records + ); + /** @var Product[] $products */ + $products = $this->doctrineHelper + ->getEntityRepository(Product::class) + ->findBy(['id' => $productIds]); + foreach ($records as $record) { + foreach ($products as $product) { + $productId = $record->getValue('id'); + if ($productId == $product->getId()) { + $record->addData(['product' => $product]); + break; + } + } + } + } + } +} diff --git a/src/Marello/Bundle/ProductBundle/EventListener/Datagrid/ProductGridListener.php b/src/Marello/Bundle/ProductBundle/EventListener/Datagrid/ProductGridListener.php index a88b2150f..0824c9c26 100644 --- a/src/Marello/Bundle/ProductBundle/EventListener/Datagrid/ProductGridListener.php +++ b/src/Marello/Bundle/ProductBundle/EventListener/Datagrid/ProductGridListener.php @@ -29,7 +29,8 @@ public function onBuildBefore(BuildBefore $event) ->addSelect('i.id as image') ->addSelect('(CASE WHEN p.image IS NOT NULL THEN true ELSE false END) as hasImage') ->addSelect('IDENTITY(p.status) as status') - ->addLeftJoin('p.image', 'i'); + ->addLeftJoin('p.image', 'i') + ->addGroupBy('i.id'); $columns = $config->offsetGetByPath('[columns]'); $columns = array_merge( [ diff --git a/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/AssignAttributesToDefaultFamily.php b/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/AssignAttributesToDefaultFamily.php deleted file mode 100644 index 74b9a76ec..000000000 --- a/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/AssignAttributesToDefaultFamily.php +++ /dev/null @@ -1,117 +0,0 @@ - [ - 'searchable' => true, - 'filterable' => true, - 'filter_by' => 'exact_value', - 'sortable' => true, - ], - 'names' => [ - 'searchable' => true, - 'filterable' => true, - 'filter_by' => 'exact_value', - 'sortable' => true, - ], - 'channels' => [ - 'visible' => true - ], - 'status' => [ - 'visible' => true - ], - 'prices' => [ - 'visible' => true - ], - 'channelPrices' => [ - 'visible' => true - ], - 'taxCode' => [ - 'visible' => true - ], - 'salesChannelTaxCodes' => [ - 'visible' => true - ], - 'weight' => [ - 'visible' => true - ], - 'manufacturingCode' => [ - 'visible' => true - ], - 'warranty' => [ - 'visible' => true - ], - 'suppliers' => [ - 'visible' => true - ], - 'categories' => [ - 'visible' => true - ], - 'image' => [ - 'visible' => true - ], - ]; - - /** - * {@inheritdoc} - */ - public function load(ObjectManager $manager) - { - $this->updateProductAttributes(self::ATTRIBUTES); - $this->addGroup($manager); - } - - /** - * @param ObjectManager $manager - */ - private function addGroup(ObjectManager $manager) - { - $attributeFamilyRepository = $manager->getRepository(AttributeFamily::class); - - $defaultFamily = - $attributeFamilyRepository->findOneBy([ - 'code' => LoadDefaultAttributeFamilyData::DEFAULT_FAMILY_CODE - ]); - - $attributeGroup = $defaultFamily->getAttributeGroup(LoadDefaultAttributeFamilyData::GENERAL_GROUP_CODE); - - $configManager = $this->getConfigManager(); - foreach (self::ATTRIBUTES as $attribute => $data) { - $fieldConfigModel = $configManager->getConfigFieldModel(Product::class, $attribute); - $attributeGroupRelation = new AttributeGroupRelation(); - $attributeGroupRelation->setEntityConfigFieldId($fieldConfigModel->getId()); - $attributeGroup->addAttributeRelation($attributeGroupRelation); - } - - $manager->persist($attributeGroup); - $manager->flush(); - } - - /** - * @inheritdoc - */ - public function getDependencies() - { - return [ - LoadDefaultAttributeFamilyData::class - ]; - } -} diff --git a/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/LoadDefaultAttributeFamilyData.php b/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/LoadDefaultAttributeFamilyData.php deleted file mode 100644 index 7b45dfebf..000000000 --- a/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/LoadDefaultAttributeFamilyData.php +++ /dev/null @@ -1,102 +0,0 @@ - self::GENERAL_GROUP_LABEL, - 'groupCode' => self::GENERAL_GROUP_CODE, - 'attributes' => [], - 'groupVisibility' => false - ] - ]; - - /** - * {@inheritdoc} - */ - public function getDependencies() - { - return [ - LoadAdminUserData::class - ]; - } - - /** - * @param ObjectManager $manager - */ - public function load(ObjectManager $manager) - { - $organization = $this->getOrganization($manager); - $attributeFamily = new AttributeFamily(); - $attributeFamily->setCode(self::DEFAULT_FAMILY_CODE); - $attributeFamily->setEntityClass(Product::class); - $attributeFamily->addLabel((new LocalizedFallbackValue())->setString('Default')); - $attributeFamily->setOwner($organization); - - $this->setReference(self::DEFAULT_FAMILY_CODE, $attributeFamily); - - $this->addGroupsWithAttributesToFamily($this->data, $attributeFamily, $manager); - } - - /** - * @param ObjectManager $manager - * - * @return Organization|object - */ - private function getOrganization(ObjectManager $manager) - { - if ($this->hasReference(LoadOrganizationAndBusinessUnitData::REFERENCE_DEFAULT_ORGANIZATION)) { - return $this->getReference(LoadOrganizationAndBusinessUnitData::REFERENCE_DEFAULT_ORGANIZATION); - } else { - return $manager - ->getRepository('OroOrganizationBundle:Organization') - ->getFirst(); - } - } - - /** - * - * @param array $groupsData - * @param AttributeFamily $attributeFamily - * @param ObjectManager $manager - */ - protected function addGroupsWithAttributesToFamily( - array $groupsData, - AttributeFamily $attributeFamily, - ObjectManager $manager - ) { - foreach ($groupsData as $groupData) { - $attributeGroup = new AttributeGroup(); - $attributeGroup->addLabel((new LocalizedFallbackValue())->setString($groupData['groupLabel'])); - $attributeGroup->setIsVisible($groupData['groupVisibility']); - $attributeGroup->setCode($groupData['groupCode']); - $attributeFamily->addAttributeGroup($attributeGroup); - } - - $manager->persist($attributeFamily); - $manager->flush(); - } -} diff --git a/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/LoadDefaultProductFamilyData.php b/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/LoadDefaultProductFamilyData.php new file mode 100644 index 000000000..3b97ccabf --- /dev/null +++ b/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/LoadDefaultProductFamilyData.php @@ -0,0 +1,62 @@ +getOrganization($manager); + if ($organization) { + /** @var ProductFamilyBuilder $productFamilyBuilder */ + $productFamilyBuilder = $this->container->get('marello_product.entity.builder.product_family'); + $defaultProductFamily = $productFamilyBuilder + ->createDefaultFamily($organization) + ->addDefaultAttributeGroups() + ->getFamily(); + + $manager->persist($defaultProductFamily); + $manager->flush(); + } + } + + + /** + * @param ObjectManager $manager + * + * @return Organization|null + */ + private function getOrganization(ObjectManager $manager) + { + $queryBuilder = $manager->getRepository(Organization::class) + ->createQueryBuilder('org'); + + $organizations = $queryBuilder + ->leftJoin(AttributeFamily::class, 'family', Join::WITH, 'org.id = family.owner') + ->where($queryBuilder->expr()->isNull('family.owner')) + ->getQuery() + ->getResult(); + if (!empty($organizations)) { + return reset($organizations); + } else { + return null; + } + } +} diff --git a/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/UpdateExistingAttributesConfig.php b/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/UpdateExistingAttributesConfig.php index f0dd5008b..90bc7bfb3 100644 --- a/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/UpdateExistingAttributesConfig.php +++ b/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/UpdateExistingAttributesConfig.php @@ -76,7 +76,7 @@ public function load(ObjectManager $manager) public function getDependencies() { return [ - LoadDefaultAttributeFamilyData::class + LoadDefaultProductFamilyData::class ]; } } diff --git a/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/UpdateExistingProductsWithAttributeFamily.php b/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/UpdateExistingProductsWithAttributeFamily.php index 6b7f27b5c..4c23d8880 100644 --- a/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/UpdateExistingProductsWithAttributeFamily.php +++ b/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/UpdateExistingProductsWithAttributeFamily.php @@ -6,6 +6,7 @@ use Doctrine\Common\DataFixtures\DependentFixtureInterface; use Doctrine\Common\Persistence\ObjectManager; +use Marello\Bundle\ProductBundle\Entity\Builder\ProductFamilyBuilder; use Oro\Bundle\EntityConfigBundle\Attribute\Entity\AttributeFamily; use Marello\Bundle\ProductBundle\Entity\Product; @@ -21,7 +22,7 @@ class UpdateExistingProductsWithAttributeFamily extends AbstractFixture implemen public function getDependencies() { return [ - LoadDefaultAttributeFamilyData::class + LoadDefaultProductFamilyData::class ]; } @@ -39,7 +40,7 @@ public function load(ObjectManager $manager) } /** @var AttributeFamily $attributeFamily */ - $attributeFamily = $this->getReference(LoadDefaultAttributeFamilyData::DEFAULT_FAMILY_CODE); + $attributeFamily = $this->getReference(ProductFamilyBuilder::DEFAULT_FAMILY_CODE); foreach ($products as $product) { $product->setAttributeFamily($attributeFamily); $manager->persist($product); diff --git a/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/UpdateExistingProductsWithCategoriesCodes.php b/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/UpdateExistingProductsWithCategoriesCodes.php new file mode 100644 index 000000000..78f89789b --- /dev/null +++ b/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/UpdateExistingProductsWithCategoriesCodes.php @@ -0,0 +1,41 @@ +getRepository(Product::class) + ->findBy(['categoriesCodes' => null]); + + if (count($products) === 0) { + return; + } + foreach ($products as $product) { + foreach ($product->getCategories() as $category) { + $product->addCategoryCode($category->getCode()); + } + $manager->persist($product); + } + + $manager->flush(); + } +} diff --git a/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/UpdateExistingProductsWithChannelsCodes.php b/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/UpdateExistingProductsWithChannelsCodes.php new file mode 100644 index 000000000..056f9b59a --- /dev/null +++ b/src/Marello/Bundle/ProductBundle/Migrations/Data/ORM/UpdateExistingProductsWithChannelsCodes.php @@ -0,0 +1,41 @@ +getRepository(Product::class) + ->findBy(['channelsCodes' => null]); + + if (count($products) === 0) { + return; + } + foreach ($products as $product) { + foreach ($product->getChannels() as $channel) { + $product->addChannelCode($channel->getCode()); + } + $manager->persist($product); + } + + $manager->flush(); + } +} diff --git a/src/Marello/Bundle/ProductBundle/Migrations/Schema/MarelloProductBundleInstaller.php b/src/Marello/Bundle/ProductBundle/Migrations/Schema/MarelloProductBundleInstaller.php index 6d8ebccd3..7cc96291f 100644 --- a/src/Marello/Bundle/ProductBundle/Migrations/Schema/MarelloProductBundleInstaller.php +++ b/src/Marello/Bundle/ProductBundle/Migrations/Schema/MarelloProductBundleInstaller.php @@ -29,7 +29,7 @@ class MarelloProductBundleInstaller implements */ public function getMigrationVersion() { - return 'v1_10'; + return 'v1_12'; } /** @@ -83,8 +83,10 @@ protected function createMarelloProductProductTable(Schema $schema) $table->addColumn('warranty', 'integer', ['notnull' => false]); $table->addColumn('preferred_supplier_id', 'integer', ['notnull' => false]); $table->addColumn('tax_code_id', 'integer', ['notnull' => false]); + $table->addColumn('channels_codes', 'text', ['notnull' => false, 'comment' => '(DC2Type:text)']); + $table->addColumn('categories_codes', 'text', ['notnull' => false, 'comment' => '(DC2Type:text)']); $table->setPrimaryKey(['id']); - $table->addUniqueIndex(['sku'], 'marello_product_product_skuidx'); + $table->addUniqueIndex(['sku', 'organization_id'], 'marello_product_product_skuorgidx'); $table->addIndex(['created_at'], 'idx_marello_product_created_at', []); $table->addIndex(['updated_at'], 'idx_marello_product_updated_at', []); $table->addIndex(['product_status'], 'IDX_25845B8D197C24B8', []); diff --git a/src/Marello/Bundle/ProductBundle/Migrations/Schema/v1_11/MarelloProductBundle.php b/src/Marello/Bundle/ProductBundle/Migrations/Schema/v1_11/MarelloProductBundle.php new file mode 100644 index 000000000..a8d6d4504 --- /dev/null +++ b/src/Marello/Bundle/ProductBundle/Migrations/Schema/v1_11/MarelloProductBundle.php @@ -0,0 +1,31 @@ +changeMarelloProductProductUniqueIndex($schema); + } + + /** + * @param Schema $schema + */ + protected function changeMarelloProductProductUniqueIndex(Schema $schema) + { + $table = $schema->getTable('marello_product_product'); + $table->dropIndex('marello_product_product_skuidx'); + $table->addUniqueIndex(['sku', 'organization_id'], 'marello_product_product_skuorgidx'); + } +} diff --git a/src/Marello/Bundle/ProductBundle/Migrations/Schema/v1_12/MarelloProductBundle.php b/src/Marello/Bundle/ProductBundle/Migrations/Schema/v1_12/MarelloProductBundle.php new file mode 100644 index 000000000..6dea87861 --- /dev/null +++ b/src/Marello/Bundle/ProductBundle/Migrations/Schema/v1_12/MarelloProductBundle.php @@ -0,0 +1,28 @@ +updateMarelloProductProductTable($schema); + } + + /** + * @param Schema $schema + */ + protected function updateMarelloProductProductTable(Schema $schema) + { + $table = $schema->getTable('marello_product_product'); + $table->addColumn('channels_codes', 'text', ['notnull' => false, 'comment' => '(DC2Type:text)']); + $table->addColumn('categories_codes', 'text', ['notnull' => false, 'comment' => '(DC2Type:text)']); + } +} diff --git a/src/Marello/Bundle/ProductBundle/Provider/OrderItemProductUnitProvider.php b/src/Marello/Bundle/ProductBundle/Provider/OrderItemProductUnitProvider.php new file mode 100644 index 000000000..b2908a502 --- /dev/null +++ b/src/Marello/Bundle/ProductBundle/Provider/OrderItemProductUnitProvider.php @@ -0,0 +1,72 @@ +doctrineHelper = $doctrineHelper; + } + + /** + * {@inheritdoc} + */ + public function processFormChanges(FormChangeContextInterface $context) + { + $submittedData = $context->getSubmittedData(); + $order = $context->getForm()->getData(); + if ($order instanceof Order) { + $salesChannel = $order->getSalesChannel(); + } else { + return; + } + $productIds = []; + foreach ($submittedData[self::ITEMS_FIELD] as $item) { + $productIds[] = (int)$item['product']; + } + $data = []; + /** @var Product[] $products */ + $products = $this->getRepository()->findBySalesChannel($salesChannel->getId(), $productIds); + foreach ($products as $product) { + /** @var InventoryItem $inventoryItem */ + $inventoryItem = $product->getInventoryItems()->first(); + $unit = $inventoryItem->getProductUnit(); + if ($unit) { + $data[sprintf('%s%s', self::IDENTIFIER_PREFIX, $product->getId())] = [ + 'unit' => $unit->getName() + ]; + } + } + if (!empty($data)) { + $result = $context->getResult(); + $result[self::ITEMS_FIELD]['product_unit'] = $data; + $context->setResult($result); + } + } + + /** + * @return ProductRepository + */ + protected function getRepository() + { + return $this->doctrineHelper->getEntityRepositoryForClass(Product::class); + } +} diff --git a/src/Marello/Bundle/ProductBundle/Provider/ProductTaxCodeProvider.php b/src/Marello/Bundle/ProductBundle/Provider/ProductTaxCodeProvider.php index 427555bdd..affd97dc9 100644 --- a/src/Marello/Bundle/ProductBundle/Provider/ProductTaxCodeProvider.php +++ b/src/Marello/Bundle/ProductBundle/Provider/ProductTaxCodeProvider.php @@ -49,8 +49,7 @@ public function processFormChanges(FormChangeContextInterface $context) if ($taxCode) { $data[sprintf('%s%s', self::IDENTIFIER_PREFIX, $product->getId())] = [ 'id' => $taxCode->getId(), - 'code' => $taxCode->getCode(), - + 'code' => $taxCode->getCode() ]; } } diff --git a/src/Marello/Bundle/ProductBundle/Resources/config/oro/actions.yml b/src/Marello/Bundle/ProductBundle/Resources/config/oro/actions.yml index 0dd0ca1bb..0a8d70b86 100755 --- a/src/Marello/Bundle/ProductBundle/Resources/config/oro/actions.yml +++ b/src/Marello/Bundle/ProductBundle/Resources/config/oro/actions.yml @@ -55,7 +55,7 @@ operations: method_parameters: [$.data] attribute: $.inventoryitem - '@redirect': - route: marello_inventory_inventory_update + route: marello_inventory_inventory_view route_parameters: id: $.inventoryitem.id action_groups: diff --git a/src/Marello/Bundle/ProductBundle/Resources/config/oro/api.yml b/src/Marello/Bundle/ProductBundle/Resources/config/oro/api.yml index 6a966356c..64e61ab02 100644 --- a/src/Marello/Bundle/ProductBundle/Resources/config/oro/api.yml +++ b/src/Marello/Bundle/ProductBundle/Resources/config/oro/api.yml @@ -19,6 +19,10 @@ api: property_path: taxCode productstatus: property_path: status + channelsCodes: + exclude: true + categoriesCodes: + exclude: true createdAt: exclude: true updatedAt: diff --git a/src/Marello/Bundle/ProductBundle/Resources/config/oro/datagrids.yml b/src/Marello/Bundle/ProductBundle/Resources/config/oro/datagrids.yml index c42e53019..f48122ff2 100644 --- a/src/Marello/Bundle/ProductBundle/Resources/config/oro/datagrids.yml +++ b/src/Marello/Bundle/ProductBundle/Resources/config/oro/datagrids.yml @@ -13,6 +13,8 @@ datagrids: - p.type - p.weight - p.manufacturingCode + - p.channelsCodes + - p.categoriesCodes - p.createdAt - p.updatedAt from: @@ -31,6 +33,22 @@ datagrids: frontend_type: string inline_editing: enable: false + channels: + label: marello.product.channels.label + type: twig + frontend_type: html + template: MarelloProductBundle:Product/Datagrid/Property:channels.html.twig + renderable: false + inline_editing: + enable: false + categories: + label: marello.product.categories.label + type: twig + frontend_type: html + template: MarelloProductBundle:Product/Datagrid/Property:categories.html.twig + renderable: false + inline_editing: + enable: false manufacturingCode: label: marello.product.manufacturing_code.label frontend_type: string @@ -69,6 +87,8 @@ datagrids: sku: { data_name: p.sku } name: { data_name: name } weight: { data_name: p.weight } + channels: { data_name: p.channelsCodes } + categories: { data_name: p.categoriesCodes } createdAt: { data_name: p.createdAt } updatedAt: { data_name: p.updatedAt } default: @@ -88,6 +108,22 @@ datagrids: data_name: p.manufacturingCode type: string enabled: false + channels: + data_name: p.channelsCodes + type: choice_like + options: + field_options: + multiple: true + choices: '@marello_sales.provider.basic_sales_channels_choices->getChannels()' + enabled: false + categories: + data_name: p.categoriesCodes + type: choice_like + options: + field_options: + multiple: true + choices: '@marello_catalog.provider.categories_choices->getCategories()' + enabled: false weight: data_name: p.weight type: number diff --git a/src/Marello/Bundle/ProductBundle/Resources/config/services.yml b/src/Marello/Bundle/ProductBundle/Resources/config/services.yml index 836153d56..64600bd44 100644 --- a/src/Marello/Bundle/ProductBundle/Resources/config/services.yml +++ b/src/Marello/Bundle/ProductBundle/Resources/config/services.yml @@ -39,6 +39,7 @@ services: - '@marello_catalog.provider.categories_ids' calls: - ['setOroEntityDoctrineHelper', ['@oro_entity.doctrine_helper']] + - ['setTokenAccessor', ['@oro_security.token_accessor']] tags: - { name: twig.extension } @@ -107,6 +108,14 @@ services: tags: - { name: marello_order.order_item_data_provider, type: tax_code, priority: 20 } + marello_product.provider.order_item_product_unit_provider: + class: Marello\Bundle\ProductBundle\Provider\OrderItemProductUnitProvider + arguments: + - '@oro_entity.doctrine_helper' + tags: + - { name: marello_order.order_item_data_provider, type: product_unit, priority: 25 } + + marello_product.repository.product: class: 'Marello\Bundle\ProductBundle\Entity\Repository\ProductRepository' parent: oro_entity.abstract_repository @@ -216,8 +225,15 @@ services: tags: - { name: doctrine.event_listener, event: onFlush } + marello_product.entity.builder.product_family: + class: Marello\Bundle\ProductBundle\Entity\Builder\ProductFamilyBuilder + arguments: + - '@translator' + - '@oro_entity_config.manager.attribute_group_manager' + public: true + marello_product.provider.action_group_registry: public: true class: Marello\Bundle\ProductBundle\Provider\ActionGroupRegistryProvider arguments: - - '@oro_action.action_group_registry' \ No newline at end of file + - '@oro_action.action_group_registry' diff --git a/src/Marello/Bundle/ProductBundle/Resources/config/validation.yml b/src/Marello/Bundle/ProductBundle/Resources/config/validation.yml index 31ad2a288..67457f47f 100644 --- a/src/Marello/Bundle/ProductBundle/Resources/config/validation.yml +++ b/src/Marello/Bundle/ProductBundle/Resources/config/validation.yml @@ -2,7 +2,7 @@ Marello\Bundle\ProductBundle\Entity\Product: constraints: - Marello\Bundle\ProductBundle\Validator\Constraints\ProductSupplierRelationsDropship: ~ - Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity: - fields: sku + fields: [sku, organization] message: 'marello.product.messages.error.sku' properties: names: diff --git a/src/Marello/Bundle/ProductBundle/Resources/translations/messages.en.yml b/src/Marello/Bundle/ProductBundle/Resources/translations/messages.en.yml index cb137af73..0d22b6c23 100644 --- a/src/Marello/Bundle/ProductBundle/Resources/translations/messages.en.yml +++ b/src/Marello/Bundle/ProductBundle/Resources/translations/messages.en.yml @@ -28,6 +28,8 @@ marello: categories.label: Categories suppliers.label: Suppliers attribute_family.label: Attribute Family + channels_codes.label: Channel codes + categories_codes.label: Category codes variant: label: Variant entity_label: Variant diff --git a/src/Marello/Bundle/ProductBundle/Resources/views/Product/Datagrid/Property/categories.html.twig b/src/Marello/Bundle/ProductBundle/Resources/views/Product/Datagrid/Property/categories.html.twig new file mode 100644 index 000000000..a8a7ac820 --- /dev/null +++ b/src/Marello/Bundle/ProductBundle/Resources/views/Product/Datagrid/Property/categories.html.twig @@ -0,0 +1,6 @@ +{% set codes = record.getValue('categoriesCodes')|split('|') %} +{% for index, code in codes %} + {% if index > 0 %} + {{ marello_get_category_name_by_code(code) }}
+ {% endif %} +{% endfor %} \ No newline at end of file diff --git a/src/Marello/Bundle/ProductBundle/Resources/views/Product/Datagrid/Property/channels.html.twig b/src/Marello/Bundle/ProductBundle/Resources/views/Product/Datagrid/Property/channels.html.twig new file mode 100644 index 000000000..446f552ea --- /dev/null +++ b/src/Marello/Bundle/ProductBundle/Resources/views/Product/Datagrid/Property/channels.html.twig @@ -0,0 +1,6 @@ +{% set codes = record.getValue('channelsCodes')|split('|') %} +{% for index, code in codes %} + {% if index > 0 %} + {{ marello_get_sales_channel_name_by_code(code) }}
+ {% endif %} +{% endfor %} \ No newline at end of file diff --git a/src/Marello/Bundle/ProductBundle/Resources/views/Product/createStepTwo.html.twig b/src/Marello/Bundle/ProductBundle/Resources/views/Product/createStepTwo.html.twig index 22dc56023..1b8c9a072 100644 --- a/src/Marello/Bundle/ProductBundle/Resources/views/Product/createStepTwo.html.twig +++ b/src/Marello/Bundle/ProductBundle/Resources/views/Product/createStepTwo.html.twig @@ -6,12 +6,17 @@ {% set gridName = 'marello-product-saleschannel-extended-grid' %} {% set entity = form.vars.value %} -{% set formAction = path('marello_product_create_step_two') %} {% if entity.id %} {% oro_title_set({params : {"%name%": entity.name } }) %} {% endif %} +{% if queryParams is defined %} + {% set formAction = path('marello_product_create_step_two', queryParams) %} +{% else %} + {% set formAction = path('marello_product_create_step_two') %} +{% endif %} + {% block pageHeader %} {% if entity.id %} {% set breadcrumbs = { diff --git a/src/Marello/Bundle/ProductBundle/Tests/Functional/Controller/ProductControllerTest.php b/src/Marello/Bundle/ProductBundle/Tests/Functional/Controller/ProductControllerTest.php index 5e0534475..fd998c19f 100644 --- a/src/Marello/Bundle/ProductBundle/Tests/Functional/Controller/ProductControllerTest.php +++ b/src/Marello/Bundle/ProductBundle/Tests/Functional/Controller/ProductControllerTest.php @@ -2,8 +2,8 @@ namespace Marello\Bundle\ProductBundle\Tests\Functional\Controller; +use Marello\Bundle\ProductBundle\Entity\Builder\ProductFamilyBuilder; use Marello\Bundle\ProductBundle\Entity\Product; -use Marello\Bundle\ProductBundle\Migrations\Data\ORM\LoadDefaultAttributeFamilyData; use Marello\Bundle\ProductBundle\Provider\ProductTypesProvider; use Marello\Bundle\ProductBundle\Tests\Functional\DataFixtures\LoadProductData; use Marello\Bundle\SalesBundle\Tests\Functional\DataFixtures\LoadSalesData; @@ -57,7 +57,7 @@ public function testCreateProduct() /** @var AttributeFamily $attributeFamily */ $attributeFamily = $em ->getRepository(AttributeFamily::class) - ->findOneBy(['code' => LoadDefaultAttributeFamilyData::DEFAULT_FAMILY_CODE]); + ->findOneBy(['code' => ProductFamilyBuilder::DEFAULT_FAMILY_CODE]); $form = $crawler->selectButton('Continue')->form(); $formValues = $form->getPhpValues(); $formValues['input_action'] = 'marello_product_create'; diff --git a/src/Marello/Bundle/ProductBundle/Tests/Functional/DataFixtures/LoadProductData.php b/src/Marello/Bundle/ProductBundle/Tests/Functional/DataFixtures/LoadProductData.php index 6adc549f4..fb7976a5e 100644 --- a/src/Marello/Bundle/ProductBundle/Tests/Functional/DataFixtures/LoadProductData.php +++ b/src/Marello/Bundle/ProductBundle/Tests/Functional/DataFixtures/LoadProductData.php @@ -9,8 +9,8 @@ use Marello\Bundle\PricingBundle\Entity\AssembledPriceList; use Marello\Bundle\PricingBundle\Entity\PriceType; use Marello\Bundle\PricingBundle\Model\PriceTypeInterface; +use Marello\Bundle\ProductBundle\Entity\Builder\ProductFamilyBuilder; use Marello\Bundle\ProductBundle\Entity\Product; -use Marello\Bundle\ProductBundle\Migrations\Data\ORM\LoadDefaultAttributeFamilyData; use Marello\Bundle\SupplierBundle\Entity\Supplier; use Marello\Bundle\SalesBundle\Entity\SalesChannel; use Marello\Bundle\PricingBundle\Entity\ProductPrice; @@ -243,7 +243,7 @@ private function createProduct(array $data) $defaultAttributeFamily = $this->manager ->getRepository(AttributeFamily::class) - ->findOneBy(['code' => LoadDefaultAttributeFamilyData::DEFAULT_FAMILY_CODE]); + ->findOneBy(['code' => ProductFamilyBuilder::DEFAULT_FAMILY_CODE]); $product->setAttributeFamily($defaultAttributeFamily); $currencies = $this->addSalesChannels($product, $data); diff --git a/src/Marello/Bundle/ProductBundle/Tests/Functional/Entity/ProductTest.php b/src/Marello/Bundle/ProductBundle/Tests/Functional/Entity/ProductTest.php index ca7925aae..e73d7b4c8 100644 --- a/src/Marello/Bundle/ProductBundle/Tests/Functional/Entity/ProductTest.php +++ b/src/Marello/Bundle/ProductBundle/Tests/Functional/Entity/ProductTest.php @@ -2,7 +2,7 @@ namespace Marello\Bundle\ProductBundle\Tests\Functional\Entity; -use Marello\Bundle\ProductBundle\Migrations\Data\ORM\LoadDefaultAttributeFamilyData; +use Marello\Bundle\ProductBundle\Entity\Builder\ProductFamilyBuilder; use Oro\Bundle\EntityConfigBundle\Config\AttributeConfigHelper; use Oro\Bundle\TestFrameworkBundle\Test\WebTestCase; @@ -39,7 +39,7 @@ public function testProductIsAssignedDefaultAttributeFamily() /** @var Product $product */ $product = $this->getReference(LoadProductData::PRODUCT_1_REF); static::assertSame( - LoadDefaultAttributeFamilyData::DEFAULT_FAMILY_CODE, + ProductFamilyBuilder::DEFAULT_FAMILY_CODE, $product->getAttributeFamily()->getCode() ); } diff --git a/src/Marello/Bundle/ProductBundle/Twig/ProductExtension.php b/src/Marello/Bundle/ProductBundle/Twig/ProductExtension.php index f07ae8e2c..0c9d831ec 100644 --- a/src/Marello/Bundle/ProductBundle/Twig/ProductExtension.php +++ b/src/Marello/Bundle/ProductBundle/Twig/ProductExtension.php @@ -7,6 +7,8 @@ use Marello\Bundle\ProductBundle\Entity\Repository\ProductRepository; use Marello\Bundle\SalesBundle\Provider\ChannelProvider; use Oro\Bundle\EntityBundle\ORM\DoctrineHelper; +use Oro\Bundle\OrganizationBundle\Entity\Organization; +use Oro\Bundle\SecurityBundle\Authentication\TokenAccessorInterface; use Twig\Extension\AbstractExtension; use Twig\TwigFunction; @@ -14,21 +16,18 @@ class ProductExtension extends AbstractExtension { const NAME = 'marello_product'; - /** - * @var ChannelProvider - */ + /** @var ChannelProvider $channelProvider */ protected $channelProvider; - /** - * @var CategoriesIdsProvider - */ + /** @var CategoriesIdsProvider $categoriesIdsProvider */ protected $categoriesIdsProvider; - /** - * @var DoctrineHelper - */ + /** @var DoctrineHelper $doctrineHelper */ private $doctrineHelper; + /** @var TokenAccessorInterface $tokenAccessor */ + private $tokenAccessor; + /** * @param ChannelProvider $channelProvider * @param CategoriesIdsProvider $categoriesIdsProvider @@ -101,9 +100,15 @@ public function getProductBySku($sku) if (!$this->doctrineHelper || !$sku) { return null; } + + $organization = null; + if ($this->tokenAccessor) { + $organization = $this->tokenAccessor->getOrganization(); + } + /** @var ProductRepository $productRepository */ $productRepository = $this->doctrineHelper->getEntityRepository(Product::class); - return $productRepository->findOneBySku($sku); + return $productRepository->findOneBySku($sku, $organization); } /** @@ -113,4 +118,12 @@ public function setOroEntityDoctrineHelper(DoctrineHelper $doctrineHelper) { $this->doctrineHelper = $doctrineHelper; } + + /** + * @param TokenAccessorInterface $tokenAccessor + */ + public function setTokenAccessor(TokenAccessorInterface $tokenAccessor) + { + $this->tokenAccessor = $tokenAccessor; + } } diff --git a/src/Marello/Bundle/PurchaseOrderBundle/Controller/PurchaseOrderController.php b/src/Marello/Bundle/PurchaseOrderBundle/Controller/PurchaseOrderController.php index a15c6e4fa..8aa6cfa7f 100644 --- a/src/Marello/Bundle/PurchaseOrderBundle/Controller/PurchaseOrderController.php +++ b/src/Marello/Bundle/PurchaseOrderBundle/Controller/PurchaseOrderController.php @@ -123,11 +123,12 @@ public function createStepTwoAction(Request $request) */ protected function createStepOne(Request $request) { - $form = $this->createForm(PurchaseOrderCreateStepOneType::class); + $form = $this->createForm(PurchaseOrderCreateStepOneType::class, new PurchaseOrder()); $handler = new PurchaseOrderCreateStepOneHandler($form, $request); + $queryParams = $request->query->all(); if ($handler->process()) { - return $this->forward('MarelloPurchaseOrderBundle:PurchaseOrder:createStepTwo'); + return $this->forward('MarelloPurchaseOrderBundle:PurchaseOrder:createStepTwo', [], $queryParams); } return ['form' => $form->createView()]; @@ -142,6 +143,7 @@ protected function createStepTwo(Request $request, PurchaseOrder $purchaseOrder) { if ($request->request->get('input_action') === 'marello_purchaseorder_purchaseorder_create') { $form = $this->createForm(PurchaseOrderCreateStepOneType::class, $purchaseOrder); + $queryParams = $request->query->all(); $form->handleRequest($request); $formData = $form->all(); @@ -155,7 +157,8 @@ protected function createStepTwo(Request $request, PurchaseOrder $purchaseOrder) return [ 'form' => $form->createView(), - 'entity' => $purchaseOrder + 'entity' => $purchaseOrder, + 'queryParams' => $queryParams ]; } diff --git a/src/Marello/Bundle/PurchaseOrderBundle/Form/Type/PurchaseOrderCreateStepTwoType.php b/src/Marello/Bundle/PurchaseOrderBundle/Form/Type/PurchaseOrderCreateStepTwoType.php index 1bb787813..4acfe2291 100644 --- a/src/Marello/Bundle/PurchaseOrderBundle/Form/Type/PurchaseOrderCreateStepTwoType.php +++ b/src/Marello/Bundle/PurchaseOrderBundle/Form/Type/PurchaseOrderCreateStepTwoType.php @@ -62,11 +62,14 @@ public function buildForm(FormBuilderInterface $builder, array $options) [ 'required' => false, 'label' => 'marello.purchaseorder.expected_delivery_date.label', - 'constraints' => [ new GreaterThan( - [ - 'value' => 'today', - 'message' => 'marello.purchaseorder.expected_delivery_date.messages.error.greater_than_date' - ]) + 'constraints' => [ + new GreaterThan( + [ + 'value' => 'today', + 'message' + => 'marello.purchaseorder.expected_delivery_date.messages.error.greater_than_date' + ] + ) ] ] ) diff --git a/src/Marello/Bundle/PurchaseOrderBundle/Resources/translations/messages.en.yml b/src/Marello/Bundle/PurchaseOrderBundle/Resources/translations/messages.en.yml index 35f91e975..81ca529c6 100644 --- a/src/Marello/Bundle/PurchaseOrderBundle/Resources/translations/messages.en.yml +++ b/src/Marello/Bundle/PurchaseOrderBundle/Resources/translations/messages.en.yml @@ -26,6 +26,7 @@ marello: billing_and_shipping.label: Billing & Delivery Info shipping_address.label: Shipping Address data.label: Data + due_date.label: Due Date ui: continue: Continue sections: diff --git a/src/Marello/Bundle/PurchaseOrderBundle/Resources/views/PurchaseOrder/createStepTwo.html.twig b/src/Marello/Bundle/PurchaseOrderBundle/Resources/views/PurchaseOrder/createStepTwo.html.twig index 86646151d..cb4fd08e7 100644 --- a/src/Marello/Bundle/PurchaseOrderBundle/Resources/views/PurchaseOrder/createStepTwo.html.twig +++ b/src/Marello/Bundle/PurchaseOrderBundle/Resources/views/PurchaseOrder/createStepTwo.html.twig @@ -3,7 +3,12 @@ {% oro_title_set({params : {"%sku%": entity.sku|default('N/A'|trans) , "%name%": (entity.id ? entity.defaultName.string : '')|default('N/A'|trans) } }) %} -{% set formAction = path('marello_purchaseorder_purchaseorder_create_step_two') %} +{% if queryParams is defined %} + {% set formAction = path('marello_purchaseorder_purchaseorder_create_step_two', queryParams) %} +{% else %} + {% set formAction = path('marello_purchaseorder_purchaseorder_create_step_two') %} +{% endif %} + {% block navButtons %} {{ parent() }} diff --git a/src/Marello/Bundle/PurchaseOrderBundle/Tests/Functional/Controller/PurchaseOrderControllerTest.php b/src/Marello/Bundle/PurchaseOrderBundle/Tests/Functional/Controller/PurchaseOrderControllerTest.php index e7bf67fa9..eb922b022 100644 --- a/src/Marello/Bundle/PurchaseOrderBundle/Tests/Functional/Controller/PurchaseOrderControllerTest.php +++ b/src/Marello/Bundle/PurchaseOrderBundle/Tests/Functional/Controller/PurchaseOrderControllerTest.php @@ -374,7 +374,7 @@ public function testErrorDueDateCreateAction() $this->assertHtmlResponseStatusCodeEquals($result, Response::HTTP_OK); $html = $crawler->html(); - $this->assertContains('Due date must be greater than', $html); + $this->assertContains('Expected Delivery date must be greater than today', $html); } /** diff --git a/src/Marello/Bundle/RefundBundle/Resources/config/oro/navigation.yml b/src/Marello/Bundle/RefundBundle/Resources/config/oro/navigation.yml index 6721068c6..a5fdc5baf 100644 --- a/src/Marello/Bundle/RefundBundle/Resources/config/oro/navigation.yml +++ b/src/Marello/Bundle/RefundBundle/Resources/config/oro/navigation.yml @@ -7,8 +7,6 @@ navigation: extras: routes: ['marello_refund_*'] position: 40 - - tree: application_menu: children: diff --git a/src/Marello/Bundle/RefundBundle/Resources/views/Refund/update.html.twig b/src/Marello/Bundle/RefundBundle/Resources/views/Refund/update.html.twig index 41c656777..a40a067ee 100644 --- a/src/Marello/Bundle/RefundBundle/Resources/views/Refund/update.html.twig +++ b/src/Marello/Bundle/RefundBundle/Resources/views/Refund/update.html.twig @@ -65,7 +65,6 @@ {{ UI.renderProperty('oro.ui.created_at'|trans, entity.createdAt|date) }} {{ UI.renderProperty('oro.ui.updated_at'|trans, entity.updatedAt|date) }} {{ UI.renderProperty('marello.order.payment_method.label'|trans, entity.order.paymentMethod) }} - {{ UI.renderProperty('marello.order.payment_reference.label'|trans, entity.order.paymentReference) }}
{{ totals }}
diff --git a/src/Marello/Bundle/RefundBundle/Resources/views/Refund/view.html.twig b/src/Marello/Bundle/RefundBundle/Resources/views/Refund/view.html.twig index b5145d7d2..3f53e0642 100644 --- a/src/Marello/Bundle/RefundBundle/Resources/views/Refund/view.html.twig +++ b/src/Marello/Bundle/RefundBundle/Resources/views/Refund/view.html.twig @@ -38,7 +38,6 @@ )}} {{ UI.renderProperty('marello.order.order_reference.label'|trans, entity.order.orderReference) }} {{ UI.renderProperty('marello.order.payment_method.label'|trans, entity.order.paymentMethod) }} - {{ UI.renderProperty('marello.order.payment_reference.label'|trans, entity.order.paymentReference) }} {{ UI.renderProperty('oro.ui.created_at'|trans, entity.order.createdAt|date) }} {{ UI.renderProperty('oro.ui.updated_at'|trans, entity.order.updatedAt|date) }} @@ -74,7 +73,6 @@ {{ UI.renderProperty('oro.ui.created_at'|trans, entity.createdAt|date) }} {{ UI.renderProperty('oro.ui.updated_at'|trans, entity.updatedAt|date) }} {{ UI.renderProperty('marello.order.payment_method.label'|trans, entity.order.paymentMethod) }} - {{ UI.renderProperty('marello.order.payment_reference.label'|trans, entity.order.paymentReference) }} {{ totals }} diff --git a/src/Marello/Bundle/RefundBundle/Tests/Functional/Controller/RefundControllerTest.php b/src/Marello/Bundle/RefundBundle/Tests/Functional/Controller/RefundControllerTest.php index a9f8a63c0..9108151b0 100644 --- a/src/Marello/Bundle/RefundBundle/Tests/Functional/Controller/RefundControllerTest.php +++ b/src/Marello/Bundle/RefundBundle/Tests/Functional/Controller/RefundControllerTest.php @@ -55,8 +55,9 @@ public function testUpdateRefund() $this->assertHtmlResponseStatusCodeEquals($result, Response::HTTP_OK); $form = $crawler->selectButton('Save and Close')->form(); - $form['marello_refund[items][0][quantity]'] = 1; - $form['marello_refund[items][0][refundAmount]'] = 100; + $key = array_key_first ($form->get('marello_refund[items]')); + $form[sprintf('marello_refund[items][%d][quantity]', $key)] = 1; + $form[sprintf('marello_refund[items][%d][refundAmount]', $key)] = 100; $result = $this->client->getResponse(); $this->assertHtmlResponseStatusCodeEquals($result, Response::HTTP_OK); diff --git a/src/Marello/Bundle/ReportBundle/Resources/config/oro/datagrids.yml b/src/Marello/Bundle/ReportBundle/Resources/config/oro/datagrids.yml index 680f51a55..ef58d9cbb 100644 --- a/src/Marello/Bundle/ReportBundle/Resources/config/oro/datagrids.yml +++ b/src/Marello/Bundle/ReportBundle/Resources/config/oro/datagrids.yml @@ -96,13 +96,9 @@ datagrids: select: - oi.productName - oi.productSku - - product.createdAt as createdAt - SUM(oi.quantity) AS quantitySold from: - { table: MarelloOrderBundle:OrderItem, alias: oi } - join: - left: - - { join: oi.product, alias: product } groupBy: oi.productSku, oi.productName columns: productSku: @@ -111,9 +107,6 @@ datagrids: productName: label: marello.product.name.label frontend_type: string - createdAt: - label: oro.ui.created_at - frontend_type: datetime quantitySold: label: marello.report.datagrid.columns.quantity_sold.label frontend_type: number @@ -122,7 +115,6 @@ datagrids: columns: productSku: { data_name: oi.productSku } productName: { data_name: oi.productName } - createdAt: { data_name: createdAt } quantitySold: { data_name: quantitySold } default: quantitySold: 'DESC' @@ -144,13 +136,9 @@ datagrids: select: - oi.productName - oi.productSku - - product.createdAt as createdAt - SUM(oi.quantity) AS quantitySold from: - { table: MarelloOrderBundle:OrderItem, alias: oi } - join: - left: - - { join: oi.product, alias: product } groupBy: oi.productSku, oi.productName columns: productSku: @@ -159,9 +147,6 @@ datagrids: productName: label: marello.product.name.label frontend_type: string - createdAt: - label: oro.ui.created_at - frontend_type: datetime quantitySold: label: marello.report.datagrid.columns.quantity_sold.label frontend_type: number @@ -170,7 +155,6 @@ datagrids: columns: productSku: { data_name: oi.productSku } productName: { data_name: oi.productName } - createdAt: { data_name: createdAt } quantitySold: { data_name: quantitySold } default: quantitySold: 'ASC' @@ -253,7 +237,7 @@ datagrids: from: - { table: MarelloOrderBundle:OrderItem, alias: oi } join: - left: + inner: - { join: MarelloReturnBundle:ReturnItem, alias: ri, conditionType: 'WITH', condition: 'oi.id = ri.orderItem' } groupBy: oi.productSku, oi.productName columns: diff --git a/src/Marello/Bundle/ReturnBundle/Controller/ReturnController.php b/src/Marello/Bundle/ReturnBundle/Controller/ReturnController.php index 80ba0d1c6..df1003b5a 100644 --- a/src/Marello/Bundle/ReturnBundle/Controller/ReturnController.php +++ b/src/Marello/Bundle/ReturnBundle/Controller/ReturnController.php @@ -81,10 +81,9 @@ public function createAction(Order $order, Request $request) } return [ - 'form' => $form->createView(), + 'form' => $form->createView() ]; } else { - throw new AccessDeniedException( $this->get('translator')->trans( 'marello.return.returnentity.messages.error.return.cannot_be_returned_without_shipment' diff --git a/src/Marello/Bundle/SalesBundle/Entity/Repository/SalesChannelRepository.php b/src/Marello/Bundle/SalesBundle/Entity/Repository/SalesChannelRepository.php index e376fafa2..a4b2269e0 100644 --- a/src/Marello/Bundle/SalesBundle/Entity/Repository/SalesChannelRepository.php +++ b/src/Marello/Bundle/SalesBundle/Entity/Repository/SalesChannelRepository.php @@ -5,6 +5,7 @@ use Doctrine\ORM\EntityRepository; use Doctrine\ORM\QueryBuilder; use Marello\Bundle\PricingBundle\Entity\ProductChannelPrice; +use Marello\Bundle\ProductBundle\Entity\Product; use Marello\Bundle\SalesBundle\Entity\SalesChannel; use Oro\Bundle\SecurityBundle\ORM\Walker\AclHelper; @@ -122,4 +123,17 @@ public function getDefaultActiveChannels() return $this->aclHelper->apply($qb)->getResult(); } + + /** + * @param Product $product + * @return SalesChannel[] + */ + public function findByProduct(Product $product) + { + $qb = $this->createQueryBuilder('sc') + ->where(':product MEMBER OF sc.products') + ->setParameters(['product' => $product]); + + return $qb->getQuery()->getResult(); + } } diff --git a/src/Marello/Bundle/SalesBundle/Entity/SalesChannel.php b/src/Marello/Bundle/SalesBundle/Entity/SalesChannel.php index 0575137e8..c2e2e3d39 100644 --- a/src/Marello/Bundle/SalesBundle/Entity/SalesChannel.php +++ b/src/Marello/Bundle/SalesBundle/Entity/SalesChannel.php @@ -2,11 +2,13 @@ namespace Marello\Bundle\SalesBundle\Entity; +use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; use Marello\Bundle\CoreBundle\Model\EntityCreatedUpdatedAtTrait; use Marello\Bundle\LocaleBundle\Model\LocalizationAwareInterface; use Marello\Bundle\LocaleBundle\Model\LocalizationTrait; use Marello\Bundle\PricingBundle\Model\CurrencyAwareInterface; +use Marello\Bundle\ProductBundle\Entity\Product; use Marello\Bundle\SalesBundle\Model\ExtendSalesChannel; use Oro\Bundle\EntityConfigBundle\Metadata\Annotation as Oro; use Oro\Bundle\IntegrationBundle\Entity\Channel; @@ -198,6 +200,28 @@ class SalesChannel extends ExtendSalesChannel implements */ protected $integrationChannel; + /** + * @var ArrayCollection + * @ORM\ManyToMany(targetEntity="Marello\Bundle\ProductBundle\Entity\Product", mappedBy="channels") + * @Oro\ConfigField( + * defaultValues={ + * "dataaudit"={ + * "auditable"=true + * }, + * "importexport"={ + * "excluded"=true + * }, + * "attribute"={ + * "is_attribute"=true + * }, + * "extend"={ + * "owner"="System" + * } + * } + * ) + */ + protected $products; + /** * @param string|null $name */ @@ -206,6 +230,15 @@ public function __construct($name = null) parent::__construct(); $this->name = $name; + $this->products = new ArrayCollection(); + } + + public function __clone() + { + if ($this->id) { + $this->id = null; + $this->products = new ArrayCollection(); + } } /** @@ -409,4 +442,29 @@ public function setIntegrationChannel(Channel $integrationChannel = null) return $this; } + + /** + * @return bool + */ + public function hasProducts() + { + return count($this->products) > 0; + } + + /** + * @param Product $product + * @return bool + */ + public function hasProduct(Product $product) + { + return $this->products->contains($product); + } + + /** + * @return ArrayCollection|SalesChannel|Product[] + */ + public function getProducts() + { + return $this->products; + } } diff --git a/src/Marello/Bundle/SalesBundle/EventListener/Datagrid/SalesChannelsDatagridListener.php b/src/Marello/Bundle/SalesBundle/EventListener/Datagrid/SalesChannelsDatagridListener.php deleted file mode 100644 index d5dd24d18..000000000 --- a/src/Marello/Bundle/SalesBundle/EventListener/Datagrid/SalesChannelsDatagridListener.php +++ /dev/null @@ -1,172 +0,0 @@ -relatedEntityClass = $relatedEntityClass; - $this->salesChannelsChoicesProvider = $salesChannelsChoicesProvider; - - $this->expressionBuilder = new Expr(); - } - - /** - * @param BuildBefore $event - */ - public function onBuildBefore(BuildBefore $event) - { - $config = $event->getConfig(); - - $this->addSelect($config); - $this->addJoin($config); - $this->addColumn($config); - $this->addSorter($config); - $this->addFilter($config); - } - - /** - * @param DatagridConfiguration $configuration - * @return string - * @throws \InvalidArgumentException when a root entity not found in the grid - */ - protected function getAlias(DatagridConfiguration $configuration) - { - $rootAlias = $configuration->getOrmQuery()->getRootAlias(); - if (!$rootAlias) { - throw new \InvalidArgumentException( - sprintf( - 'A root entity is missing for grid "%s"', - $configuration->getName() - ) - ); - } - - return $rootAlias; - } - - /** - * @return string - */ - protected function getColumnLabel() - { - return 'marello.product.channels.label'; - } - - /** - * @return string - */ - protected function getDataName() - { - return self::DATA_NAME; - } - - /** - * @return string - */ - protected function getJoinAlias() - { - return self::JOIN_ALIAS; - } - - /** - * @param DatagridConfiguration $config - */ - protected function addSelect(DatagridConfiguration $config) - { - $config->getOrmQuery() - ->addSelect( - sprintf( - 'GROUP_CONCAT( - DISTINCT CONCAT_WS(\'|\', %1$s.name, %1$s.code) SEPARATOR \';\' - ) as channels', - $this->getJoinAlias() - ) - ) - ->addSelect( - sprintf('count(%s.code) AS channelsCount', $this->getJoinAlias()) - ); - } - - /** - * @param DatagridConfiguration $config - */ - protected function addJoin(DatagridConfiguration $config) - { - $config->getOrmQuery()->addLeftJoin( - $this->getAlias($config).'.channels', - $this->getJoinAlias() - ); - } - - /** - * @param DatagridConfiguration $config - */ - protected function addColumn(DatagridConfiguration $config) - { - $config->offsetSetByPath(sprintf('[columns][%s]', $this->getDataName()), [ - 'label' => $this->getColumnLabel(), - 'type' => 'twig', - 'frontend_type' => 'html', - 'template' => 'MarelloSalesBundle:SalesChannel/Datagrid/Property:channels.html.twig', - 'renderable' => true, - 'inline_editing' => ['enable' => false] - ]); - } - - /** - * @param DatagridConfiguration $config - */ - protected function addSorter(DatagridConfiguration $config) - { - $config->offsetSetByPath( - sprintf('[sorters][columns][%s]', $this->getDataName()), - ['data_name' => 'channelsCount'] - ); - } - - /** - * @param DatagridConfiguration $config - */ - protected function addFilter(DatagridConfiguration $config) - { - $config->offsetSetByPath( - sprintf('[filters][columns][%s]', $this->getDataName()), - [ - 'type' => 'choice', - 'data_name' => $this->getJoinAlias() . '.code', - 'enabled' => false, - 'options' => [ - 'field_options' => [ - 'multiple' => true, - 'choices' => $this->salesChannelsChoicesProvider->getChannels() - ] - ] - ] - ); - } -} diff --git a/src/Marello/Bundle/SalesBundle/Resources/config/services.yml b/src/Marello/Bundle/SalesBundle/Resources/config/services.yml index 3603147bf..7e9f7ebe2 100644 --- a/src/Marello/Bundle/SalesBundle/Resources/config/services.yml +++ b/src/Marello/Bundle/SalesBundle/Resources/config/services.yml @@ -119,14 +119,6 @@ services: tags: - { name: kernel.event_listener, event: oro_datagrid.orm_datasource.result.after.marello-sales-channel-groups, method: onResultAfter } - marello_sales.event_listener.datagrid.products_grid: - class: 'Marello\Bundle\SalesBundle\EventListener\Datagrid\SalesChannelsDatagridListener' - arguments: - - 'Marello\Bundle\ProductBundle\Entity\Product' - - '@marello_sales.provider.basic_sales_channels_choices' - tags: - - { name: kernel.event_listener, event: oro_datagrid.datagrid.build.before.marello-products-grid, method: onBuildBefore } - marello_sales.datagrid.saleschannelgroup.action_permission_provider: class: 'Marello\Bundle\SalesBundle\Datagrid\SalesChannelGroupActionPermissionProvider' public: true diff --git a/src/Marello/Bundle/SalesBundle/Resources/translations/messages.en.yml b/src/Marello/Bundle/SalesBundle/Resources/translations/messages.en.yml index ffeac0c76..fc869bebd 100644 --- a/src/Marello/Bundle/SalesBundle/Resources/translations/messages.en.yml +++ b/src/Marello/Bundle/SalesBundle/Resources/translations/messages.en.yml @@ -19,6 +19,7 @@ marello: channel_type.label: Type owner.label: Owner localization.label: Localization + products.label: Products controller.message.saved: Sales Channel saved form.select_saleschannels: Select Sales Channels form.select_saleschannel: Select Sales Channel diff --git a/src/Marello/Bundle/SalesBundle/Resources/views/SalesChannel/Datagrid/Property/channels.html.twig b/src/Marello/Bundle/SalesBundle/Resources/views/SalesChannel/Datagrid/Property/channels.html.twig deleted file mode 100644 index 95cd7252c..000000000 --- a/src/Marello/Bundle/SalesBundle/Resources/views/SalesChannel/Datagrid/Property/channels.html.twig +++ /dev/null @@ -1,7 +0,0 @@ -{% set channels = record.getValue('channels')|split(';') %} -{% for index, channelSet in channels %} - {% set values = channelSet|split('|') %} - {% if values|length > 0 %} - {{ values[0] }}
- {% endif %} -{% endfor %} \ No newline at end of file diff --git a/src/Marello/Bundle/SalesBundle/Tests/Unit/Twig/SalesExtensionTest.php b/src/Marello/Bundle/SalesBundle/Tests/Unit/Twig/SalesExtensionTest.php index 88ce57f1f..eda508a65 100644 --- a/src/Marello/Bundle/SalesBundle/Tests/Unit/Twig/SalesExtensionTest.php +++ b/src/Marello/Bundle/SalesBundle/Tests/Unit/Twig/SalesExtensionTest.php @@ -35,6 +35,10 @@ public function testGetFunctions() new TwigFunction( 'marello_sales_has_active_channels', [$this->extension, 'checkActiveChannels'] + ), + new TwigFunction( + 'marello_get_sales_channel_name_by_code', + [$this->extension, 'getChannelNameByCode'] ) ], $this->extension->getFunctions() @@ -81,4 +85,41 @@ public function checkActiveChannelsDataProvider() ], ]; } + + /** + * @param $expectedChannel + * @param $code + * @param $expectedResult + * @dataProvider getChannelNameByCodeDataProvider + */ + public function testGetChannelNameByCode($expectedChannel, $code, $expectedResult) + { + $this->salesChannelRepository + ->expects(static::once()) + ->method('findOneBy') + ->willReturn($expectedChannel); + + static::assertEquals($expectedResult, $this->extension->getChannelNameByCode($code)); + } + + /** + * @return array[] + */ + public function getChannelNameByCodeDataProvider() + { + $channel = new SalesChannel('channel1'); + $channel->setCode('test'); + return [ + 'with active channels' => [ + 'expectedChannel' => $channel, + 'code' => 'test', + 'expectedResult' => 'channel1', + ], + 'without active channels' => [ + 'expectedChannel' => null, + 'code' => 'MySalesChannelCode', + 'expectedResult' => 'MySalesChannelCode' + ], + ]; + } } diff --git a/src/Marello/Bundle/SalesBundle/Twig/SalesExtension.php b/src/Marello/Bundle/SalesBundle/Twig/SalesExtension.php index dc1926c1b..df7d8e28a 100644 --- a/src/Marello/Bundle/SalesBundle/Twig/SalesExtension.php +++ b/src/Marello/Bundle/SalesBundle/Twig/SalesExtension.php @@ -32,6 +32,10 @@ public function getFunctions() new TwigFunction( 'marello_sales_has_active_channels', [$this, 'checkActiveChannels'] + ), + new TwigFunction( + 'marello_get_sales_channel_name_by_code', + [$this, 'getChannelNameByCode'] ) ]; } @@ -48,6 +52,21 @@ public function checkActiveChannels() return false; } + /** + * @param string $code + * @return string + */ + public function getChannelNameByCode($code) + { + $channel = $this->salesChannelRepository + ->findOneBy(['code' => $code]); + if ($channel) { + return $channel->getName(); + } + + return $code; + } + /** * Returns the name of the extension. * diff --git a/src/Marello/Bundle/TaxBundle/EventListener/Datagrid/TaxCodeDatagridListener.php b/src/Marello/Bundle/TaxBundle/EventListener/Datagrid/TaxCodeDatagridListener.php index d1976f7cd..0a529b546 100644 --- a/src/Marello/Bundle/TaxBundle/EventListener/Datagrid/TaxCodeDatagridListener.php +++ b/src/Marello/Bundle/TaxBundle/EventListener/Datagrid/TaxCodeDatagridListener.php @@ -96,7 +96,7 @@ protected function addSelect(DatagridConfiguration $config) { $config->getOrmQuery()->addSelect( sprintf('%s.code AS %s', $this->getJoinAlias(), $this->getDataName()) - ); + )->addGroupBy(sprintf('%s.code', $this->getJoinAlias())); } /**