diff --git a/src/Model/Mutation/Inquiry/CreateInquiryMutation.php b/src/Model/Mutation/Inquiry/CreateInquiryMutation.php new file mode 100644 index 000000000..6204276a4 --- /dev/null +++ b/src/Model/Mutation/Inquiry/CreateInquiryMutation.php @@ -0,0 +1,84 @@ +createInquiryDataFromArgument($argument); + $inquiry = $this->inquiryFacade->create($inquiryData); + + $this->inquiryMailFacade->sendMail($inquiry); + + return true; + } catch (ProductNotFoundException) { + throw new ProductNotFoundUserError(sprintf('Product with UUID "%s" not found', $argument['input']['productUuid'])); + } + } + + /** + * @param \Overblog\GraphQLBundle\Definition\Argument $argument + * @return \Shopsys\FrameworkBundle\Model\Inquiry\InquiryData + */ + protected function createInquiryDataFromArgument(Argument $argument): InquiryData + { + $input = $argument['input']; + + $inquiryData = $this->inquiryDataFactory->create($this->domain->getId()); + $product = $this->productFacade->getByUuid($input['productUuid']); + + $inquiryData->firstName = $input['firstName']; + $inquiryData->lastName = $input['lastName']; + $inquiryData->email = $input['email']; + $inquiryData->telephone = $input['telephone']; + $inquiryData->companyName = $input['companyName'] ?? null; + $inquiryData->companyNumber = $input['companyNumber'] ?? null; + $inquiryData->companyTaxNumber = $input['companyTaxNumber'] ?? null; + $inquiryData->note = $input['note'] ?? null; + $inquiryData->customerUser = $this->currentCustomerUser->findCurrentCustomerUser(); + $inquiryData->product = $product; + + return $inquiryData; + } +} diff --git a/src/Model/Resolver/Price/PriceQuery.php b/src/Model/Resolver/Price/PriceQuery.php index 7be491dc5..83fa65fb0 100644 --- a/src/Model/Resolver/Price/PriceQuery.php +++ b/src/Model/Resolver/Price/PriceQuery.php @@ -15,6 +15,7 @@ use Shopsys\FrameworkBundle\Model\Product\Pricing\ProductPrice; use Shopsys\FrameworkBundle\Model\Product\Product; use Shopsys\FrameworkBundle\Model\Product\ProductCachedAttributesFacade; +use Shopsys\FrameworkBundle\Model\Product\ProductTypeEnum; use Shopsys\FrameworkBundle\Model\Transport\Transport; use Shopsys\FrameworkBundle\Model\Transport\TransportPriceCalculation; use Shopsys\FrameworkBundle\Model\Transport\TransportPriceProvider; @@ -61,6 +62,10 @@ public function __construct( */ public function priceByProductQuery(Product|array $data): ProductPrice { + if ($this->isProductUponInquiry($data)) { + return ProductPrice::createHiddenProductPrice(); + } + if ($data instanceof Product) { $productPrice = $this->productCachedAttributesFacade->getProductSellingPrice($data); } else { @@ -74,6 +79,17 @@ public function priceByProductQuery(Product|array $data): ProductPrice return $productPrice; } + /** + * @param \Shopsys\FrameworkBundle\Model\Product\Product|array $data + * @return bool + */ + protected function isProductUponInquiry(Product|array $data): bool + { + $productType = $data instanceof Product ? $data->getProductType() : $data['product_type']; + + return $productType === ProductTypeEnum::TYPE_INQUIRY; + } + /** * @param \Shopsys\FrameworkBundle\Model\Payment\Payment $payment * @param string|null $cartUuid diff --git a/src/Model/Resolver/Products/DataMapper/ProductArrayFieldMapper.php b/src/Model/Resolver/Products/DataMapper/ProductArrayFieldMapper.php index 02a1e1612..d649c5d3a 100644 --- a/src/Model/Resolver/Products/DataMapper/ProductArrayFieldMapper.php +++ b/src/Model/Resolver/Products/DataMapper/ProductArrayFieldMapper.php @@ -13,6 +13,7 @@ use Shopsys\FrameworkBundle\Model\Product\Flag\FlagFacade; use Shopsys\FrameworkBundle\Model\Product\ProductElasticsearchProvider; use Shopsys\FrameworkBundle\Model\Product\ProductFrontendLimitProvider; +use Shopsys\FrameworkBundle\Model\Product\ProductTypeEnum; use Shopsys\FrontendApiBundle\Model\Parameter\ParameterWithValuesFactory; class ProductArrayFieldMapper @@ -244,4 +245,22 @@ public function isVisible(array $data): bool return false; } + + /** + * @param array $data + * @return bool + */ + public function isInquiryType(array $data): bool + { + return $data['product_type'] === ProductTypeEnum::TYPE_INQUIRY; + } + + /** + * @param array $data + * @return string + */ + public function getProductType(array $data): string + { + return $data['product_type']; + } } diff --git a/src/Model/Resolver/Products/DataMapper/ProductEntityFieldMapper.php b/src/Model/Resolver/Products/DataMapper/ProductEntityFieldMapper.php index a39f2b526..130f2ad07 100644 --- a/src/Model/Resolver/Products/DataMapper/ProductEntityFieldMapper.php +++ b/src/Model/Resolver/Products/DataMapper/ProductEntityFieldMapper.php @@ -13,6 +13,7 @@ use Shopsys\FrameworkBundle\Model\Product\Collection\ProductCollectionFacade; use Shopsys\FrameworkBundle\Model\Product\Product; use Shopsys\FrameworkBundle\Model\Product\ProductFrontendLimitProvider; +use Shopsys\FrameworkBundle\Model\Product\ProductTypeEnum; use Shopsys\FrameworkBundle\Model\Product\ProductVisibilityFacade; use Shopsys\FrameworkBundle\Model\Seo\HreflangLinksFacade; use Shopsys\FrontendApiBundle\Model\Parameter\ParameterWithValuesFactory; @@ -222,4 +223,22 @@ public function getVariantsCount(Product $product): Promise return $this->productsSellableCountByIdsBatchLoader->load($variantIds); } + + /** + * @param \Shopsys\FrameworkBundle\Model\Product\Product $product + * @return bool + */ + public function isInquiryType(Product $product): bool + { + return $product->getProductType() === ProductTypeEnum::TYPE_INQUIRY; + } + + /** + * @param \Shopsys\FrameworkBundle\Model\Product\Product $product + * @return string + */ + public function getProductType(Product $product): string + { + return $product->getProductType(); + } } diff --git a/src/Model/Resolver/Query/MoneyResolverMap.php b/src/Model/Resolver/Query/MoneyResolverMap.php index eedc70dc6..b7ec5d425 100644 --- a/src/Model/Resolver/Query/MoneyResolverMap.php +++ b/src/Model/Resolver/Query/MoneyResolverMap.php @@ -6,6 +6,7 @@ use GraphQL\Language\AST\StringValueNode; use Overblog\GraphQLBundle\Resolver\ResolverMap; +use Shopsys\FrameworkBundle\Component\Money\HiddenMoney; use Shopsys\FrameworkBundle\Component\Money\Money; use Shopsys\FrameworkBundle\Model\Customer\User\Role\CustomerUserRole; use Shopsys\FrontendApiBundle\Component\Price\MoneyFormatterHelper; @@ -34,16 +35,28 @@ protected function map(): array ]; } + /** + * @param \Shopsys\FrameworkBundle\Component\Money\Money $money + * @return bool + */ + protected function shouldShowAmount(Money $money): bool + { + if ($money instanceof HiddenMoney) { + return false; + } + + return + $this->security->getUser() === null || + $this->security->isGranted(CustomerUserRole::ROLE_API_CUSTOMER_SEES_PRICES); + } + /** * @param \Shopsys\FrameworkBundle\Component\Money\Money $money * @return string */ protected function serializeMoney(Money $money): string { - if ( - $this->security->getUser() === null || - $this->security->isGranted(CustomerUserRole::ROLE_API_CUSTOMER_SEES_PRICES) - ) { + if ($this->shouldShowAmount($money)) { return MoneyFormatterHelper::formatWithMaxFractionDigits($money); } diff --git a/src/Resources/config/graphql-types/EnumType/ProductTypeEnumDecorator.types.yaml b/src/Resources/config/graphql-types/EnumType/ProductTypeEnumDecorator.types.yaml new file mode 100644 index 000000000..8cef01771 --- /dev/null +++ b/src/Resources/config/graphql-types/EnumType/ProductTypeEnumDecorator.types.yaml @@ -0,0 +1,12 @@ +ProductTypeEnumDecorator: + type: enum + decorator: true + config: + description: "One of possible product types" + values: + BASIC: + value: '@=constant("Shopsys\\FrameworkBundle\\Model\\Product\\ProductTypeEnum::TYPE_BASIC")' + description: "Basic product" + INQUIRY: + value: '@=constant("Shopsys\\FrameworkBundle\\Model\\Product\\ProductTypeEnum::TYPE_INQUIRY")' + description: "Product with inquiry form instead of add to cart button" diff --git a/src/Resources/config/graphql-types/ModelType/Inquiry/Input/CreateInquiryInputDecorator.types.yaml b/src/Resources/config/graphql-types/ModelType/Inquiry/Input/CreateInquiryInputDecorator.types.yaml new file mode 100644 index 000000000..136fe91a1 --- /dev/null +++ b/src/Resources/config/graphql-types/ModelType/Inquiry/Input/CreateInquiryInputDecorator.types.yaml @@ -0,0 +1,52 @@ +CreateInquiryInputDecorator: + type: input-object + inherits: + - 'NameInputObjectDecorator' + - 'TelephoneInputObjectDecorator' + decorator: true + config: + fields: + productUuid: + type: "Uuid!" + description: "Product UUID" + email: + type: "String!" + description: "The customer's email address" + validation: + - NotBlank: + message: "Please enter email" + - Email: + message: "Please enter valid email" + - Length: + max: 255 + maxMessage: "Email cannot be longer than {{ limit }} characters" + companyName: + type: "String" + description: "The customer’s company name" + validation: + - Length: + max: 100 + maxMessage: "Company name cannot be longer than {{ limit }} characters" + companyNumber: + type: "String" + description: "The customer’s company identification number" + validation: + - Length: + max: 50 + maxMessage: "Identification number cannot be longer than {{ limit }} characters" + - Regex: + pattern: '/^[0-9]+$/' + message: "Please fill in numbers only" + companyTaxNumber: + type: "String" + description: "The customer’s company tax number" + validation: + - Length: + max: 50 + maxMessage: "Tax number cannot be longer than {{ limit }} characters" + - Regex: + pattern: '/^[0-9A-Z]*([0-9]+[A-Z]+|[A-Z]+[0-9]+)[0-9A-Z]*$/' + message: "Please check Tax number format" + note: + type: "String" + description: "Customer's question or note to the inquiry product" diff --git a/src/Resources/config/graphql-types/ModelType/Product/ProductDecorator.types.yaml b/src/Resources/config/graphql-types/ModelType/Product/ProductDecorator.types.yaml index 8c527a5ed..754cb494a 100644 --- a/src/Resources/config/graphql-types/ModelType/Product/ProductDecorator.types.yaml +++ b/src/Resources/config/graphql-types/ModelType/Product/ProductDecorator.types.yaml @@ -74,3 +74,7 @@ ProductDecorator: resolve: '@=query("filesByProductPromiseQuery", value)' isVisible: type: "Boolean!" + isInquiryType: + type: "Boolean!" + productType: + type: "ProductTypeEnum!" diff --git a/src/Resources/config/graphql-types/Mutation/MutationDecorator.types.yaml b/src/Resources/config/graphql-types/Mutation/MutationDecorator.types.yaml index f42b288eb..c881d10f5 100644 --- a/src/Resources/config/graphql-types/Mutation/MutationDecorator.types.yaml +++ b/src/Resources/config/graphql-types/Mutation/MutationDecorator.types.yaml @@ -179,6 +179,14 @@ MutationDecorator: type: ContactFormInput! validation: cascade resolve: "@=mutation('contactFormMutation', args, validator)" + CreateInquiry: + type: Boolean! + description: "Send the inquiry for the product" + args: + input: + type: CreateInquiryInput! + validation: cascade + resolve: "@=mutation('createInquiryMutation', args)" AddNewCustomerUser: type: "CustomerUser!" description: "Add new customer user to customer"