aviacommerce / avia Goto Github PK
View Code? Open in Web Editor NEWopen source e-commerce framework
Home Page: https://www.aviacommerce.org/
License: MIT License
open source e-commerce framework
Home Page: https://www.aviacommerce.org/
License: MIT License
We have fixed the routes as per the payment providers for now. This needs to be refactored such that there is just one endpoint for success and one for failure.
At controller level, the handling should be generic. Any provider specific code should go inside avia_payments or gringotts.
On any error or payment cancellation for Payubiz error should be handled gracefully.
The first categories that are listed on product category page are fetched by hardcoded taxon id
.
:code
s are currently hardcoded and it will become much simpler to maintain changes to them if they are defined in a single place. commentTo deliver emails in the background Bamboo offers deliver_later on our Mailers so that it won't block our requests.
By default delivering later uses Bamboo.TaskSupervisorStrategy. This strategy sends the email right away, but does so in the background without linking to the calling process, so errors in the mailer won't bring down your app.
To create a custom strategy we can implement Bamboo.DeliverLaterStrategy. For example, strategies for adding emails to a background processing queue such as exq or toniq.
Create a mix task to seed data for the core
app.
The applicaitons
needed to seed data should be loaded only during the seed operation.
Current Situation:
Currently we are directly using the hardcoded strings wherever in need.
like for payment types chk
and ccd
is hardcoded wherever needed.
Also for usual messages and error messages we are hardcoding the lines.
Intended situation:
In future if we want to make any change we will have to change the every occurrence of hardcoded string in the app.
There should be a single point of truth/source where once a change is made, will reflect in the entire system.
Proposed Fix
Create a Constant File, where will be can use maps for different types of strings.
E.g: PAYMENT_TYPES = %{chk: 'chk', ccd: 'ccd'}
Enums can also be used.
Any other suggestions are welcomed π
Schema.User
Schema.LineItem
Schema.Order
(add the action
argument)@required_fields
, @password_fields
to @create_fields
and @update_fields
Model.User
Snitch.Tools.QueryHelper
User
. Write assertions on the changeset itself. Cover all error cases.get
and get_all
.Excellent documentation on how to write doctests. See an example in Model.LineItem
and Model.LineItemTest
user_with_address
in test/support/factory.ex
@oyeb gave a suggestion to use create method in models with single map
type param
only.
Since the current implementation needs the required number of fields in a schema to be used in create params.
new suggestion
create(required1, required2, optional\\ %{}), do: ...
OR
create(attributes\\ %{}), do: ...
PR 161 introduced many breaking changes as all entities that were associated with variants
will now be associated with products
. Tests that failed due to these changes were fixed, but the docs
, variable and method naming need to be fixed. Refer the PR 161 diff to refactor the changes
Following things need to be fixed on Taxonomy edit page
Though the changeset handles unique_constraint
errors, none have been specified in the migrations. This leads to duplication when core.seed
is run more than once.
Create an issue template so that users
are able to report bugs in a proper manner.
For help
https://help.github.com/articles/creating-an-issue-template-for-your-repository/
Create promotions creation UI in admin interface.
List of tasks for create flow:-
List of tasks for READ, UPDATE, DELETE flow:-
Card
changeset
functions must be like the ones in Schema.Payment
, with an action
argument. This will make it easy to write the Model.Card
with CardPayments
. Is the Card
created along with the parent CardPayment
or separately? If created with the parent, use cast_assoc
in CardPayment
's changeset.Card
. Write assertions on the changeset itself. Cover all error cases.get
and get_all
.Excellent documentation on how to write doctests. See an example in Model.LineItem
and Model.LineItemTest
I just for fun refactored a couple of functions in avia/apps/admin_app/lib/admin_app/order/order.ex.
The get_rummage function contains a risky String.to_atom call (see https://hexdocs.pm/elixir/String.html#to_atom/1). I removed it. The rest of the changes could speak for itself (feel free to ask if you have questions). There is one order_list function now. I have no elixir editor from where I work, so maybe there are errors in the code.
def order_list(order_state, sort_order) do
orders =
get_rummage(sort_order)
|> query_orders(order_state)
|> load_orders()
case order_state do
"complete" -> orders
_ -> orders |> Enum.filter(fn order -> filter_order?(order.packages, order_state) end)
end
end
defp filter_order?(packages, "pending"), do:
Enum.member?(packages, "processing")
defp filter_order?(packages, "unshipped"), do:
Enum.member?(packages, "ready")
defp filter_order?(packages, "shipped"), do:
Enum.any?(packages, fn package ->
package.state == "shipped" || package.state == "delivered"
end)
defp get_rummage(sort_order) do
case sort_order do
nil ->
%{}
"asc" ->
%{
sort: %{field: :inserted_at, order: :asc}
}
"desc" ->
%{
sort: %{field: :inserted_at, order: :desc}
}
end
end
defp query_orders(rummage, order_state) do
{queryable, _rummage} = Order.rummage(rummage)
case order_state do
complete" -> from(p in queryable, where: p.state == "complete")
_ -> from(p in queryable, where: p.state == "confirmed")
end
end
Pivotal #155950953
reference: keyword
source_location_id: source stock location (optional)
destination_location_id: destination stock location (required)
number: unique identifier to be used in UI
Exposes only Create, Get, Get all functions. Just like stock movement. This should not be deleted/updated. Instead will be offset using new record.
The scenario needs to be handled where the selected variation-theme has empty option types on editing a product and creating variants for it.
Steps to reproduce the error:
Snitch is not a library, it's an app. So our users won't be adding {:snitch, "> 0.1"}
to their deps
. They'll have to clone it and actually edit Snitch itself.
snitch_core
comes with its own Repo
. β
:snitch_core
OTP app.Snitch
is like a demo app that uses the snitch_core
library. In that case,
snitch_core
should be added as a dependency.snitch_core
must fetch stuff like Repo config, Gateway config from outside the lib.snitch_core
provides some mix tasks to seed the user's Repo.snitch_core
if we do the above?Create helper function for multi-select
the way it has been done for other phoenix form inputs in the admin app.
Hi I am trying to run the application but getting the following error:
ERROR in src/app/landing/components/lp-banner/lp-banner.component.ts(14,26): error TS2314: Generic type 'NguCarousel<T>' requires 1 type argument(s).
src/app/product/components/product-detail-page/product-images/product-images.component.ts(55,7): error TS2322: Type 'number' is not assignable to type 'CarouselInterval'.
src/app/product/components/product-detail-page/product-images/product-images.component.ts(56,7): error TS2322: Type '{ visible: boolean; pointStyles:
string; }' is not assignable to type 'boolean'.
src/app/product/components/product-detail-page/product-images/product-images.component.ts(90,7): error TS2322: Type 'true' is not assignable to type 'Touch'.
I think it is asking to provide a type to generic, but even if I do so it still throws an error.
I already saw a similar issue here, but no solution provided. uiuniversal/ngu-carousel#106
Can anyone please help I am stuck. Apologies if I missed anything, Please let me know if you need any extra information. Thanks.
At present we don't have any rule for limiting the access of domain, model and schema functions outside snitch_core.
Allowing model functions
to be used outside snitch_core.
pros
cons
Allowing all the access to snitch_core through domain modules
.
These are my views, I would like other people to put in their inputs and we can create some conventions and rules around that to be followed in
snitch
.
We need to come up with an approach to handle product deletions.
Usually, products are present in many users carts. Either this should not be allowed or we should just deactivate(soft delete) the product and show to the user in the wish list that the product has been deactivated or something.
Product listing page lists all sell-able product on index page. This page needs pagination support.
Admin can only activate product to active once, next time it won't work.
Step to reproduce:
draft
section to active
(It will change the state)active
. (It wont allow to change the state until we visit to product page without any filters)Please leave a comment with your feedback, suggestion or request.
We are listening and would give priority to things which the community needs.
If a listing is in in-active
state and there are no variants for it then trying to change the state to active does not do anything. No errors are shown and the status also does not change.
However, if variants are created for the product then in that case the status can be changed from in-active
to active
.
When all umbrella apps are started from project root using mix phx.server
then the image files uploaded for product and brands are save at root level
According to definitions of the state machine, an order in cart
state has no address.
But, the DefaultMachine.add_addresses
can associate an address, then fail if shipment computation fails -- without rolling back the address. π
This will keep the order in cart
state, with an address.
That's not what we want:
internal server error
. So currently user is not able to reset password.UI for forget password page is misplaced.
changeset
TaxCategory
schema.Admin should be able to set position of categories in taxonomy by dragging it from UI.
When splitting an "individual" item that is ordered in a large quantity, the split does not consider previously prepared packages that still have some space in them.
[120 g, 110 g]
List of bins/packages after processing this item:
[120, 110, 140, 140, 20]
List of bins/packages after processing this item:
[140, 150, 140, 100]
At present amount
is being sent to the API for the transition from address -> payment but, it should be calculated in the backend and updated rather than doing this.
Current naming and dir structure
|-- apps
|-- core
|-- config
|-- lib
|-- core
|-- snitch
|-- data
|-- schema
|-- model
|-- tools
|-- seed
Suggested naming and dir structure
|-- apps
|-- snitch
|-- config
|-- lib
|-- snitch
|-- data
|-- schema
|-- model
|-- tools
|-- seed
We missed a few details in #18 π’
core/
" in lib/
.query_helper.ex
is inside query_helper/
. Let's move it Data
namespace? We can keep the folder perhaps.action
argument. It should be the first argument, not the last. The last an be made a keyword
if need be.seed/
from lib
and place them in priv/repo/
__using__
macro in schema.ex
, model.ex
, domain.ex
must self-alias, so that when we do use Snitch.Data.Schema
, we don't have to also do alias Snitch.Data.Schema
.
No longer relevant.
use Snitch.Data.Schema
is allowed only in lib/data/schema/*.ex
, and likewise for Model
and Domain
. Everywhere else, they should be aliased.
use
a module to become like it. For example, all schemas "use" Ecto.Schema
, because they are schemas.factory.ex
No longer relevant
QueryHelper.update
args should be swapped, struct first and then params.Model
functions have this argument: id_or_instance
.id_or_struct
(because there's no concept of "instance" in Elixir).ids
if the function does not load the record from DB, and <struct_name>
if the function actually operates on the struct
.$ tree lib
lib
βββ core
βΒ Β βββ application.ex
βΒ Β βββ data
βΒ Β βΒ Β βββ model
βΒ Β βΒ Β βΒ Β βββ line_item.ex
βΒ Β βΒ Β βΒ Β βββ model.ex
βΒ Β βΒ Β βΒ Β βββ order.ex
βΒ Β βΒ Β βΒ Β βββ stock
βΒ Β βΒ Β βΒ Β βββ stock.ex
βΒ Β βΒ Β βΒ Β βββ stock_item.ex
βΒ Β βΒ Β βΒ Β βββ stock_location.ex
βΒ Β βΒ Β βββ schema
βΒ Β βΒ Β βββ address.ex
βΒ Β βΒ Β βββ country.ex
βΒ Β βΒ Β βββ line_item.ex
βΒ Β βΒ Β βββ order.ex
βΒ Β βΒ Β βββ schema.ex
βΒ Β βΒ Β βββ state.ex
βΒ Β βΒ Β βββ stock
βΒ Β βΒ Β βΒ Β βββ stock.ex
βΒ Β βΒ Β βΒ Β βββ stock_item.ex
βΒ Β βΒ Β βΒ Β βββ stock_location.ex
βΒ Β βΒ Β βββ user.ex
βΒ Β βΒ Β βββ variant.ex
βΒ Β βββ domain
βΒ Β βΒ Β βββ domain.ex
βΒ Β βΒ Β βββ stock
βΒ Β βΒ Β βββ inventory.ex
βΒ Β βββ repo.ex
βΒ Β βββ seed
βΒ Β βΒ Β βββ country_state_seed.ex
βΒ Β βββ tools
βΒ Β βββ helpers
βΒ Β βββ query_helper
βΒ Β βββ query_helper.ex
βββ snitch.ex
A user should be able to add a review only once for a product
. At present can multiple reviews per order.
As of now both the schemas
exist but the functionality for their relationship is not present.
Associate product
schema with property
schema such that products can be associated properties.
payment_method
model should have a source field so as to differentiate the gateway using which the payment was made.
Currently there is not setup doc for this app, create one.
Things in setup doc:
postgres
Please feel free to add what extra will be needed π
The QueryHelper
brings convenience at a cost. It has polymorphic clauses for update
, delete
, get
which accept integers/nil in addition to struct
.
QH
if we only accept Ecto.Schema
structs, because these struct have a lot of metadata.Ecto.Repo
functions accept a keyword
list of DB options.Ecto.Repo
at compile time (or fetch it from the keyword
list)commit_if_valid/2
because it serves no purpose.QueryHelper
.def delete(schema, id, repo) when is_integer(id) do
with {:ok, instance} <- repo.get(schema, id) do
delete(schema, instance, repo)
else
{:error, :not_found}
end
end
The with
clause always fails because Ecto.Repo.get/2)
always returns Ecto.Schema.t
or nil
and never a tuple.
Creating Updating an order without by removing its LineItem
s fails because of the way we compute order.total
:
** (Enum.EmptyError) empty error
(elixir) lib/enum.ex:1855: Enum.reduce/2
(snitch_core) lib/core/data/schema/order.ex:92: Snitch.Data.Schema.Order.compute_totals/1
(snitch_core) lib/core/tools/helpers/query_helper/query_helper.ex:37: Snitch.Tools.QueryHelper.update/4
This is also related to the way we handle money.
line_item.total
(if they are all in the same currency, the other case is not handled).#Money<0, :USD>
, but why USD
?line_items
, The order.total
must be set to zero... but in which currency?There are 2 issues here:
[]
?With the basic e-commerce platform released we are set to start working on supporting plugins for aviacommerce.
Plugins for aviacommerce would work similar to how magento and shopify plugins work. A seller can install these apps in their online store and would be able to use the features of this plugin. For eg. If a seller installs MailChimp plugin/application then they would get following functionalities with it broadly categorised in 2 categoreis:-
The platform would be powered by at least 200 to 300 plugins. Every seller will integrate an almost unique combination of plugins. From this we can infer a few things about the behaviour of plugins:-
mix.exs
file.So, the need is to have the plugins(and their associated code) included individually for each seller. Aviacommerce is a platform supporting multi-tenancy.
The problem ahead of us is to come up with an approach to achieve this dynamic nature of code injection for each individual seller using the plugins(service specific).
One of the approach we discussed initially was a way to highjack the control flow. For the sake of discussing this approach lets take a basic requirement of sending an event trigger for product view to a marketing service. A naive implementation would be triggering an async job/worker to send the event. Code for this would go in the products controller show
method if we donβt have support for plugins in place. However, If we have plugins support then weβd have a plugin with code(service specific). On activation this plugin code would highjack the product controller show
method , trigger the async code and return control to the platform products controller show
method.
This is a very basic use case and does not provide solution for exposing views from the plugins.
...
Sellers should be able to use the user interface to activate plugins to integrate third party services. These activations happen in realtime.
For the sake of POC we can just implement the plugins for services which just send a trigger to a third party service. For eg. sending orders list to sendgrid, sending events to segment.com and similar user cases.
Ejabbered(Erlang project) has implemented a plugin approach similar to what we want in the system.
This isn't really an issue, but more of a question:
Why did you choose to model Products and Product Variants in a single table? Are there any concerns with challenges of having to manage name/description/meta-description/etc of many product variants at once?
Why not a "Products" table that contains common fields and a "Variants" table that contains variant-specific attributes like prices, options, etc?
Address
record is created if the user does not use a saved address as billing/shipping address during checkout.Add a new Address record. From the old record remove the association with the user. All orders using the old address will thus remain intact.
null
should suffice. Or we could make a join table (that would be overkill as User:Address::1:n
, and not m:n
).The package creation/splitting is heavily dependant on zones. Prevent deletion of the last available zone.
This looks like a neat project! Although, I have a question. The website proclaims that this is an "Open Source E-Commerce framework", but I cannot find an open source license anywhere in the code. Do you have one in mind?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.