Commit Graph

438 Commits

Author SHA1 Message Date
Matt-Yorkley
9851c9a762 Merge pull request #6678 from Matt-Yorkley/soft-deprecate-tax-rates
Introduce soft-deprecation strategy when modifying tax rates
2021-02-05 13:16:40 +01:00
Matt-Yorkley
389e149ded Wrap updates in a transaction block
Ensures the operation will be rolled ack if either saving the new record or deleting the old record fail
2021-02-03 11:54:54 +00:00
Pau Pérez Fabregat
d48aa4a73f Merge pull request #6748 from coopdevs/dont-fetch-vos-with-deleted-variant
Do not fetch VOs with deleted variant
2021-02-02 15:38:29 +01:00
Pau Perez
6584f510e8 Remove now dead code 2021-02-01 16:38:40 +01:00
Pau Perez
060530cda8 Do not fetch VOs with deleted variant
In the line below we filter them out in Ruby so it's a waste of
resources. The fundamental difference is that `#includes` and
`#references` results in LEFT JOINs, whereas `#joins` results in INNER
JOIN, and because there's a default scope on `deleted_at IS NULL`, these
are not included in the result set.

This however, requires us to move away from the current algorithm but
unfortunately we can't refactor it completely yet.

Before:

```sql
SELECT *
  FROM "variant_overrides"
  LEFT OUTER
  JOIN "spree_variants"
    ON "spree_variants"."id"              =  "variant_overrides"."variant_id"
   AND "spree_variants"."deleted_at" IS NULL
  LEFT OUTER
  JOIN "spree_products"
    ON "spree_products"."id"              =  "spree_variants"."product_id"
   AND "spree_products"."deleted_at" IS NULL
 WHERE "variant_overrides"."permission_revoked_at" IS NULL
   AND "variant_overrides"."hub_id" IN (
    SELECT "enterprises"."id"
      FROM "enterprises"
    INNER
      JOIN "enterprise_roles"
        ON "enterprise_roles"."enterprise_id" =  "enterprises"."id"
    WHERE (enterprise_roles.user_id          =  ?)
      AND (sells                             != 'none')
 ORDER BY name)
```

After:

```sql
SELECT "variant_overrides".*
  FROM "variant_overrides"
 INNER
  JOIN "spree_variants"
    ON "spree_variants"."id"              =  "variant_overrides"."variant_id"
   AND "spree_variants"."deleted_at" IS NULL
 INNER
  JOIN "spree_products"
    ON "spree_products"."id"              =  "spree_variants"."product_id"
   AND "spree_products"."deleted_at" IS NULL
 WHERE "variant_overrides"."permission_revoked_at" IS NULL
   AND "variant_overrides"."hub_id" IN (
    SELECT "enterprises"."id"
      FROM "enterprises"
    INNER
      JOIN "enterprise_roles"
        ON "enterprise_roles"."enterprise_id" =  "enterprises"."id"
    WHERE (enterprise_roles.user_id          =  ?)
      AND (sells                             != 'none')
 ORDER BY name)
```

This is covered in the test suite by
spec/controllers/admin/variant_overrides_controller_spec.rb:72. It keeps
passing so we're good to go.
2021-02-01 14:47:51 +01:00
Matt-Yorkley
3da21ce2bd Add historical note to CartService
Useful background when applying upstream fixes from Spree::OrderPopulator, and means grepping for OrderPopulator doesn't come up empty.
2021-01-30 16:57:05 +00:00
Cillian O'Ruanaidh
899dffec96 When an order is cancelled by a customer send an email to the shop.
Fixes #6435 i.e. If the customer paid for their order by Stripe/Paypal then the Enterprise needs to know that the order was cancelled in order to arrange a refund.  Refunds are not automatically processed when an order is cancelled.

This will send a very basic email to the shop, it only includes a link to view the cancelled order in the admin area initially.

I created a CustomerOrderCancellation object here because orders can be cancelled in two ways (1) by the customer, so an email should be sent to the shop. (2) by the shop, so an email doesn't need to be sent. However the code for cancelling order happens in Order#cancel via the state machine. Rather than passing some sort of parameter into #cancel to indicate whether it is a customer or shop cancelled order it might be clearer to have a CustomerOrderCancellation object, there could be other differences between customer or shop cancelled orders in future maybe.
2021-01-29 11:23:05 +00:00
Pau Pérez Fabregat
c3897dd3df Merge pull request #6643 from coopdevs/customer-balance-frontoffice
Customer balance frontoffice
2021-01-27 19:55:56 +01:00
Matt-Yorkley
49c616c33c Extract tax rate transition logic to service 2021-01-21 14:50:14 +00:00
Andy Brett
e31d566f7f Merge pull request #6283 from luisramos0/sets
Move sets out of app/models to app/services/sets
2021-01-20 19:22:15 -08:00
Pau Perez
d18e79ab19 Move query object to app/queries/ and doc it 2021-01-20 18:23:22 +01:00
Pau Perez
20abaaa950 Reuse outstanding balance statement across queries
Instead of relying on Spree::Order#outstanding_balance we make us of the
result set `balance_value` computed column. So, we ask PostgreSQL to
compute it instead of Ruby and then serialize it from that computed
column. That's a bit faster to compute that way and let's reuse logic.

We hide this new implementation under this features' toggle so it's only
used when enabled. We want hit the old behaviour by default.
2021-01-20 18:23:22 +01:00
Pau Perez
681a009eb6 Extract outstanding balance SQL CASE/WHEN 2021-01-20 18:23:22 +01:00
Pau Pérez Fabregat
9689fe2edf Merge pull request #6384 from andrewpbrett/fix-product-descriptions
correctly display '&' and ' ' in product descriptions
2021-01-14 17:00:16 +01:00
Luis Ramos
19b12092a0 Fix rubocop issues and adapt exceptions file 2021-01-14 09:41:07 +00:00
Luis Ramos
96a351ad0e Adapt usage of Sets to their new location 2021-01-14 09:41:07 +00:00
Luis Ramos
187b4a1fc2 Add Sets namespace to each set file 2021-01-14 09:41:07 +00:00
Luis Ramos
8e65d29b02 Move sets to specific services namespace 2021-01-14 09:41:07 +00:00
Andy Brett
bbd7fd0350 handle nil product descriptions 2021-01-13 20:57:27 -08:00
Andy Brett
5723a79409 check for content.present? 2021-01-11 21:21:24 -08:00
Pau Perez
dfed20d634 Consider awaiting_return, returned in balance
These states are reached when the order is complete and shipped. An
admin can create a new return authorization, which will set the order in
`awaiting_return` state. It's only after, when we call
`return_authorization#receive` that the return authorization moves to
`received` state and the order to `returned`.

You can do so from the UI by editing the return authorization and
clicking on Receive. However, we didn't find any order in such state in
UK, FR and AU. The UX is quite obfuscated. That must be why no users
clicked on it.

The `returned` state cannot count for the balance as is, since some of
the products are returned to the shop. That's enough for now.
2021-01-11 15:50:19 +01:00
Pau Perez
aa3fc71626 Consider resumed & payment orders in balance
These order states are already taken care of because they fall in the
`WHEN state IS NOT NULL` case.
2021-01-11 15:50:19 +01:00
Pau Perez
5018e88a34 Consider all states prior to checkout in balance 2021-01-11 15:50:19 +01:00
Pau Perez
398467e7ed Hide new balance impl. under feature toggle
This makes it possible to deploy it without releasing it to users since
the toggle is not enabled for anyone.

It aims to make the balance calculation consistent across pages.
2021-01-11 15:50:19 +01:00
Pau Perez
2e9bae0ea5 Move relation includes out of query object
This query object is meant to be reusable but those includes are
context-specific and will likely not be needed when reusing the query
elsewhere. If we keep them there, chances are next dev might not notice
it and will introduce a performance regression.
2021-01-11 15:50:19 +01:00
Pau Perez
46d997406a Filter out cart orders when fetching customers
We only care about non-cart orders and skipping carts, saves PostgreSQL
query planner to go through thousands of records in production use cases
(my food hub).

We go from

```sql
 ->  Index Scan using index_spree_orders_on_customer_id on spree_orders  (cost=0.42..12049.45 rows=152002 width=15) (actual time=0.015..11.703 rows=13867 loops=1)
```

to

```sql
->  Index Scan using index_spree_orders_on_customer_id on spree_orders  (cost=0.42..12429.46 rows=10802 width=15) (actual time=0.025..17.705 rows=9954 loops=1)
```
2021-01-11 15:50:19 +01:00
Pau Perez
93cdca85c6 Return 0 balance when the customer has no orders 2021-01-11 15:50:19 +01:00
Pau Perez
d8872bc785 Explain why Arel can't be used in statement 2021-01-11 15:50:19 +01:00
Pau Perez
1e9a1f340e Don't consider order total when it is canceled 2021-01-11 15:50:19 +01:00
Pau Perez
e404225de0 Extract query object 2021-01-11 15:50:19 +01:00
Matt-Yorkley
b7ecf4791a Extract more sanitizing logic from Api::ProductSerializer and make service more generic/re-usable. 2021-01-09 01:07:11 +00:00
Andy Brett
59527ab38a refactor filter to a service 2021-01-08 13:37:18 -08:00
Matt-Yorkley
fe0a0395d8 Remove DEFAULT_PAGE constants 2021-01-05 19:07:46 +00:00
Paulo Vilarinho
1c5f6e7222 apply pagination data concern to orders controller 2021-01-04 20:22:14 -03:00
Andy Brett
a745fceb53 Merge pull request #6469 from andrewpbrett/sca-backend
Allow SCA cards to be setup and charged offline for subscriptions
2020-12-11 14:23:12 -08:00
Andy Brett
f50577b489 refactor cloner to use ivars 2020-12-10 11:42:28 -08:00
Andy Brett
7a03882314 re-refactor cart_service 2020-12-08 14:37:16 -08:00
Andy Brett
c70ea44091 show specific error message when add-to-cart fails 2020-12-08 14:37:16 -08:00
Andy Brett
a466886a32 fix rubocop warnings 2020-12-08 07:52:42 -08:00
Andy Brett
fea7576ac1 update CreditCardCloner to find existing clone 2020-12-08 07:52:42 -08:00
Andy Brett
cad8a018f9 put SetupIntent on the connected Stripe account 2020-12-08 07:52:41 -08:00
Andy Brett
215d1bbe20 create js setup intent when authing shop 2020-12-08 07:52:41 -08:00
Matt-Yorkley
4394d2fe43 Fix tag_rules ForbiddenAttributes errors
Example error:
Tag Rules creating allows creation of rules of each type
     Failure/Error: expect(tag_rule.preferred_shipping_method_tags).to eq "volunteers-only"

       expected: "volunteers-only"
            got: ""

       (compared using ==)
     # ./spec/features/admin/tag_rules_spec.rb:81:in `block (3 levels) in <top (required)>'
2020-11-27 14:00:29 +00:00
Matt-Yorkley
7ef0056225 Fix invoice rendering issue
Setting `locals: { :@order => order }` no longer works; `@order` is not set as expected in the partial. Fixes various errors eg:

Failure/Error: = "#{@order.number}"

     ActionView::Template::Error:
       undefined method `number' for nil:NilClass
     # ./app/views/spree/admin/orders/invoice.html.haml:14:in `_app_views_spree_admin_orders_invoice_html_haml__1740595365701113578_70025078036080'
     # ./app/services/invoice_renderer.rb:3:in `render_to_string'
     # ./app/controllers/spree/admin/orders_controller.rb:89:in `invoice'
2020-11-27 14:00:29 +00:00
Matt-Yorkley
e1c1574931 Refactor BulkInvoiceService to use ActiveJob
Removes use of #handle_asynchronously, which we need to do elsewhere. Fixes:
BulkInvoiceService#start_pdf_job starts a background process to create a pdf with multiple invoices
      Failure/Error:
        expect do
          service.start_pdf_job [1, 2]
        end.to enqueue_job Delayed::PerformableMethod

        expected to enqueue exactly 1 jobs, but enqueued 0
      # ./spec/services/bulk_invoice_service_spec.rb:8:in `block (3 levels) in <top (required)>'
2020-11-27 14:00:29 +00:00
Matt-Yorkley
54a4952dc5 Fix ForbiddenAttributesError on tag rules 2020-11-27 14:00:28 +00:00
Matt-Yorkley
34bfd877cc Fix #bulk_update in EnterprisesController 2020-11-27 14:00:28 +00:00
Luis Ramos
9bbef16804 Converting all calls to ActiveRelation#sum to use a symbol with &
This is only applicable to database columns, if we are summing using a method in the model than the & is required!
2020-11-27 13:59:46 +00:00
Matt-Yorkley
0b18b0dc0a Include Calculator attributes in PaymentMethod nested attributes and DRY repeated code 2020-11-17 19:04:26 +00:00
Matt-Yorkley
d225294b6b Extract to PermittedAttributes::Calculator 2020-11-17 18:51:48 +00:00