コード例 #1
0
        public async Task <JObject> GetOrderAsync(string ID, DecodedToken decodedToken)
        {
            var supplierID = ID.Split("-")[1];
            var me         = await _oc.Me.GetAsync(accessToken : decodedToken.AccessToken);

            Require.That(decodedToken.CommerceRole == CommerceRole.Seller || supplierID == me.Supplier.ID, new ErrorCode("Unauthorized", 401, $"You are not authorized view this order"));
            try
            {
                var type =
                    Assembly.GetExecutingAssembly().GetTypeByAttribute <SupplierSyncAttribute>(attribute => attribute.SupplierID == supplierID) ??
                    Assembly.GetExecutingAssembly().GetTypeByAttribute <SupplierSyncAttribute>(attribute => attribute.SupplierID == "Generic");
                if (type == null)
                {
                    throw new MissingMethodException($"Command for {supplierID} is unavailable");
                }

                var command = (ISupplierSyncCommand)Activator.CreateInstance(type, _settings);
                var method  = command.GetType().GetMethod($"GetOrderAsync", BindingFlags.Public | BindingFlags.Instance);
                if (method == null)
                {
                    throw new MissingMethodException($"Get Order Method for {supplierID} is unavailable");
                }

                return(await(Task <JObject>) method.Invoke(command, new object[] { ID, decodedToken }));
            }
            catch (MissingMethodException mex)
            {
                throw new Exception(JsonConvert.SerializeObject(new ApiError()
                {
                    Data      = new { decodedToken, OrderID = ID },
                    ErrorCode = mex.Message,
                    Message   = $"Missing Method for: {supplierID ?? "Invalid Supplier"}"
                }));
            }
        }
コード例 #2
0
        public async Task <Payment> AuthorizePayment(
            OrderCloudIntegrationsCreditCardPayment payment,
            string userToken,
            string merchantID
            )
        {
            Require.That((payment.CreditCardID != null) || (payment.CreditCardDetails != null),
                         new ErrorCode("CreditCard.CreditCardAuth", 400, "Request must include either CreditCardDetails or CreditCardID"));

            var cc = await GetMeCardDetails(payment, userToken);

            Require.That(payment.IsValidCvv(cc), new ErrorCode("CreditCardAuth.InvalidCvv", 400, "CVV is required for Credit Card Payment"));
            Require.That(cc.Token != null, new ErrorCode("CreditCardAuth.InvalidToken", 400, "Credit card must have valid authorization token"));
            Require.That(cc.xp.CCBillingAddress != null, new ErrorCode("Invalid Bill Address", 400, "Credit card must have a billing address"));

            var orderWorksheet = await _oc.IntegrationEvents.GetWorksheetAsync <HSOrderWorksheet>(OrderDirection.Incoming, payment.OrderID);

            var order = orderWorksheet.Order;

            Require.That(!order.IsSubmitted, new ErrorCode("CreditCardAuth.AlreadySubmitted", 400, "Order has already been submitted"));

            var ccAmount = orderWorksheet.Order.Total;

            var ocPaymentsList = (await _oc.Payments.ListAsync <HSPayment>(OrderDirection.Incoming, payment.OrderID, filters: "Type=CreditCard"));
            var ocPayments     = ocPaymentsList.Items;
            var ocPayment      = ocPayments.Any() ? ocPayments[0] : null;

            if (ocPayment == null)
            {
                throw new CatalystBaseException("Payment.MissingCreditCardPayment", "Order is missing credit card payment");
            }
            try
            {
                if (ocPayment?.Accepted == true)
                {
                    if (ocPayment.Amount == ccAmount)
                    {
                        return(ocPayment);
                    }
                    else
                    {
                        await VoidTransactionAsync(ocPayment, order, userToken);
                    }
                }
                var call = await _cardConnect.AuthWithoutCapture(CardConnectMapper.Map(cc, order, payment, merchantID, ccAmount));

                ocPayment = await _oc.Payments.PatchAsync <HSPayment>(OrderDirection.Incoming, order.ID, ocPayment.ID, new PartialPayment { Accepted = true, Amount = ccAmount });

                return(await _oc.Payments.CreateTransactionAsync(OrderDirection.Incoming, order.ID, ocPayment.ID, CardConnectMapper.Map(ocPayment, call)));
            }
            catch (CreditCardAuthorizationException ex)
            {
                ocPayment = await _oc.Payments.PatchAsync <HSPayment>(OrderDirection.Incoming, order.ID, ocPayment.ID, new PartialPayment { Accepted = false, Amount = ccAmount });

                await _oc.Payments.CreateTransactionAsync(OrderDirection.Incoming, order.ID, ocPayment.ID, CardConnectMapper.Map(ocPayment, ex.Response));

                throw new CatalystBaseException($"CreditCardAuth.{ex.ApiError.ErrorCode}", ex.ApiError.Message, ex.Response);
            }
        }
コード例 #3
0
        public async Task <HSSupplier> GetMySupplier(string supplierID, DecodedToken decodedToken)
        {
            var me = await _oc.Me.GetAsync(accessToken : decodedToken.AccessToken);

            Require.That(supplierID == me.Supplier.ID,
                         new ErrorCode("Unauthorized", 401, $"You are only authorized to view {me.Supplier.ID}."));
            return(await _oc.Suppliers.GetAsync <HSSupplier>(supplierID));
        }
コード例 #4
0
        private async Task <CurrencySymbol> GetCurrencyForUser(string userToken)
        {
            var buyerUserGroups = await _oc.Me.ListUserGroupsAsync <HSLocationUserGroup>(opts => opts.AddFilter(u => u.xp.Type == "BuyerLocation"), userToken);

            var currency = buyerUserGroups.Items.FirstOrDefault(u => u.xp.Currency != null)?.xp?.Currency;

            Require.That(currency != null, new ErrorCode("Exchange Rate Error", 400, "Exchange Rate Not Defined For User"));
            return((CurrencySymbol)currency);
        }
コード例 #5
0
        public async Task <TaxCertificate> UpdateAsync(string locationID, TaxCertificate cert, DecodedToken decodedToken)
        {
            await EnsureUserCanManageLocationResaleCert(locationID, decodedToken);

            var buyerID = locationID.Split('-')[0];
            var address = await _oc.Addresses.GetAsync <HSAddressBuyer>(buyerID, locationID);

            Require.That(address.xp.AvalaraCertificateID == cert.ID, new ErrorCode("Insufficient Access", 403, $"User cannot modofiy this cert"));
            var updatedCert = await _avalara.UpdateCertificateAsync(cert.ID, cert, address);

            return(updatedCert);
        }
コード例 #6
0
        public async Task <HSSupplier> UpdateSupplier(string supplierID, PartialSupplier supplier, DecodedToken decodedToken)
        {
            var me = await _oc.Me.GetAsync(accessToken : decodedToken.AccessToken);

            Require.That(decodedToken.CommerceRole == CommerceRole.Seller || supplierID == me.Supplier.ID, new ErrorCode("Unauthorized", 401, $"You are not authorized to update supplier {supplierID}"));
            var currentSupplier = await _oc.Suppliers.GetAsync <HSSupplier>(supplierID);

            var updatedSupplier = await _oc.Suppliers.PatchAsync <HSSupplier>(supplierID, supplier);

            // Update supplier products only on a name change
            if (currentSupplier.Name != supplier.Name || currentSupplier.xp.Currency.ToString() != supplier.xp.Currency.Value)
            {
                var productsToUpdate = await _oc.Products.ListAllAsync <HSProduct>(
                    supplierID : supplierID,
                    accessToken : decodedToken.AccessToken
                    );

                ApiClient supplierClient = await _apiClientHelper.GetSupplierApiClient(supplierID, decodedToken.AccessToken);

                if (supplierClient == null)
                {
                    throw new Exception($"Default supplier client not found. SupplierID: {supplierID}");
                }
                var configToUse = new OrderCloudClientConfig
                {
                    ApiUrl       = decodedToken.ApiUrl,
                    AuthUrl      = decodedToken.AuthUrl,
                    ClientId     = supplierClient.ID,
                    ClientSecret = supplierClient.ClientSecret,
                    GrantType    = GrantType.ClientCredentials,
                    Roles        = new[]
                    {
                        ApiRole.SupplierAdmin,
                        ApiRole.ProductAdmin
                    },
                };
                var ocClient = new OrderCloudClient(configToUse);
                await ocClient.AuthenticateAsync();

                var token = ocClient.TokenResponse.AccessToken;
                foreach (var product in productsToUpdate)
                {
                    product.xp.Facets["supplier"] = new List <string>()
                    {
                        supplier.Name
                    };
                    product.xp.Currency = supplier.xp.Currency;
                }
                await Throttler.RunAsync(productsToUpdate, 100, 5, product => ocClient.Products.SaveAsync(product.ID, product, accessToken: token));
            }

            return(updatedSupplier);
        }
コード例 #7
0
        public virtual async Task SendSingleTemplateEmailMultipleRcpts(string from, List <EmailAddress> tos, string templateID, object templateData)
        {
            Require.That(templateID != null, new ErrorCode("SendgridError", 501, "Required Sengrid template ID not configured in app settings"));
            {
                var fromEmail = new EmailAddress(from);
                var msg       = MailHelper.CreateSingleTemplateEmailToMultipleRecipients(fromEmail, tos, templateID, templateData);
                var response  = await _client.SendEmailAsync(msg);

                if (!response.IsSuccessStatusCode)
                {
                    throw new Exception("Error sending sendgrid email");
                }
            }
        }
コード例 #8
0
        public async Task SendSingleTemplateEmailMultipleRcptsAttachment(string from, List <EmailAddress> tos, string templateID, object templateData, CloudAppendBlob fileReference, string fileName)
        {
            Require.That(templateID != null, new ErrorCode("SendgridError", 501, "Required Sengrid template ID not configured in app settings"));
            {
                var fromEmail = new EmailAddress(from);
                var msg       = MailHelper.CreateSingleTemplateEmailToMultipleRecipients(fromEmail, tos, templateID, templateData);
                using (var stream = await fileReference.OpenReadAsync())
                {
                    await msg.AddAttachmentAsync(fileName, stream);
                }
                var response = await _client.SendEmailAsync(msg);

                if (!response.IsSuccessStatusCode)
                {
                    throw new Exception("Error sending sendgrid email");
                }
            }
        }
コード例 #9
0
        private async Task ValidateOrderAsync(HSOrderWorksheet worksheet, OrderCloudIntegrationsCreditCardPayment payment, string userToken)
        {
            Require.That(
                !worksheet.Order.IsSubmitted,
                new ErrorCode("OrderSubmit.AlreadySubmitted", 400, "Order has already been submitted")
                );

            var shipMethodsWithoutSelections = worksheet?.ShipEstimateResponse?.ShipEstimates?.Where(estimate => estimate.SelectedShipMethodID == null);

            Require.That(
                worksheet?.ShipEstimateResponse != null &&
                shipMethodsWithoutSelections.Count() == 0,
                new ErrorCode("OrderSubmit.MissingShippingSelections", 400, "All shipments on an order must have a selection"), shipMethodsWithoutSelections
                );

            Require.That(
                !worksheet.LineItems.Any() || payment != null,
                new ErrorCode("OrderSubmit.MissingPayment", 400, "Order contains standard line items and must include credit card payment details"),
                worksheet.LineItems
                );
            var lineItemsInactive = await GetInactiveLineItems(worksheet, userToken);

            Require.That(
                !lineItemsInactive.Any(),
                new ErrorCode("OrderSubmit.InvalidProducts", 400, "Order contains line items for products that are inactive"), lineItemsInactive
                );

            try
            {
                // ordercloud validates the same stuff that would be checked on order submit
                await _oc.Orders.ValidateAsync(OrderDirection.Incoming, worksheet.Order.ID);
            } catch (OrderCloudException ex) {
                // credit card payments aren't accepted yet, so ignore this error for now
                // we'll accept the payment once the credit card auth goes through (before order submit)
                var errors = ex.Errors.Where(ex => ex.ErrorCode != "Order.CannotSubmitWithUnaccceptedPayments");
                if (errors.Any())
                {
                    throw new CatalystBaseException("OrderSubmit.OrderCloudValidationError", "Failed ordercloud validation, see Data for details", errors);
                }
            }
        }
コード例 #10
0
ファイル: ListArgs.cs プロジェクト: djsteinmetz/headstart
        private static string FindSortableProp(Type type, string path)
        {
            if (path.StartsWith("xp."))
            {
                return(path);
            }

            var queue = new Queue <string>(path.Split('.'));
            var prop  = type.GetProperty(queue.Dequeue(), BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);

            Require.That(prop != null, ErrorCodes.List.InvalidProperty, new InvalidPropertyError(type, path));
            //TODO: evaluate this requirement for reference sake
            //Require.That(prop.HasAttribute<SortableAttribute>(), ErrorCodes.List.InvalidSortProperty, new InvalidPropertyError(type, path));
            var result = prop?.Name;

            if (queue.Any())
            {
                result += "." + FindSortableProp(prop.PropertyType, queue.JoinString("."));
            }
            return(result);
        }
コード例 #11
0
        private void ValidateLineItemStatusChange(List <HSLineItem> previousLineItemStates, LineItemStatusChanges lineItemStatusChanges, VerifiedUserType userType)
        {
            /* need to validate 2 things on a lineitem status change
             *
             * 1) user making the request has the ability to make that line item change based on usertype
             * 2) there are sufficient amount of the previous quantities for each lineitem
             */

            // 1)
            var allowedLineItemStatuses = LineItemStatusConstants.ValidLineItemStatusSetByUserType[userType];

            Require.That(allowedLineItemStatuses.Contains(lineItemStatusChanges.Status), new ErrorCode("Not authorized to set this status on a lineItem", 400, $"Not authorized to set line items to {lineItemStatusChanges.Status}"));

            // 2)
            var areCurrentQuantitiesToSupportChange = lineItemStatusChanges.Changes.All(lineItemChange =>
            {
                return(ValidateCurrentQuantities(previousLineItemStates, lineItemChange, lineItemStatusChanges.Status));
            });

            Require.That(areCurrentQuantitiesToSupportChange, new ErrorCode("Invalid lineItem status change", 400, $"Current lineitem quantity statuses on the order are not sufficient to support the requested change"));
        }
コード例 #12
0
        public async Task SendSingleTemplateEmailSingleRcptAttachment(string from, string to, string templateID, object templateData, IFormFile fileReference)
        {
            Require.That(templateID != null, new ErrorCode("SendgridError", 501, "Required Sengrid template ID not configured in app settings"));
            {
                var fromEmail = new EmailAddress(from);
                var toEmail   = new EmailAddress(to);
                var msg       = MailHelper.CreateSingleTemplateEmail(fromEmail, toEmail, templateID, templateData);
                if (fileReference != null)
                {
                    using (var stream = fileReference.OpenReadStream())
                    {
                        await msg.AddAttachmentAsync(fileReference.FileName, stream);
                    }
                }
                var response = await _client.SendEmailAsync(msg);

                if (!response.IsSuccessStatusCode)
                {
                    throw new Exception("Error sending sendgrid email");
                }
            }
        }
コード例 #13
0
        public async Task <HSLineItem> UpsertLineItem(string orderID, HSLineItem liReq, DecodedToken decodedToken)
        {
            // get me product with markedup prices correct currency and the existing line items in parellel
            var productRequest           = _meProductCommand.Get(liReq.ProductID, decodedToken);
            var existingLineItemsRequest = _oc.LineItems.ListAllAsync <HSLineItem>(OrderDirection.Outgoing, orderID, filters: $"Product.ID={liReq.ProductID}", accessToken: decodedToken.AccessToken);
            var orderRequest             = _oc.Orders.GetAsync(OrderDirection.Incoming, orderID);
            await Task.WhenAll(productRequest, existingLineItemsRequest, orderRequest);

            var existingLineItems = await existingLineItemsRequest;
            var product           = await productRequest;
            var order             = await orderRequest;

            var li            = new HSLineItem();
            var markedUpPrice = ValidateLineItemUnitCost(orderID, product, existingLineItems, liReq);

            liReq.UnitPrice = await markedUpPrice;

            Require.That(!order.IsSubmitted, new ErrorCode("Invalid Order Status", 400, "Order has already been submitted"));

            liReq.xp.StatusByQuantity = LineItemStatusConstants.EmptyStatuses;
            liReq.xp.StatusByQuantity[LineItemStatus.Open] = liReq.Quantity;

            var preExistingLi = ((List <HSLineItem>)existingLineItems).Find(eli => LineItemsMatch(eli, liReq));

            if (preExistingLi != null)
            {
                liReq.ID = preExistingLi.ID; //ensure we do not change the line item id when updating
                li       = await _oc.LineItems.SaveAsync <HSLineItem>(OrderDirection.Incoming, orderID, preExistingLi.ID, liReq);
            }
            else
            {
                li = await _oc.LineItems.CreateAsync <HSLineItem>(OrderDirection.Incoming, orderID, liReq);
            }
            await _promotionCommand.AutoApplyPromotions(orderID);

            return(li);
        }
コード例 #14
0
ファイル: OrderCommand.cs プロジェクト: kingeric027/headstart
        private async Task EnsureUserCanAccessOrder(HSOrder order, DecodedToken decodedToken)
        {
            /* ensures user has access to order through at least 1 of 3 methods
             * 1) user submitted the order
             * 2) user has access to all orders from the location of the billingAddressID
             * 3) the order is awaiting approval and the user is in the approving group
             */

            var isOrderSubmitter = order.FromUser.Username == decodedToken.Username;

            if (isOrderSubmitter)
            {
                return;
            }

            var isUserInLocationOrderAccessGroup = await _locationPermissionCommand.IsUserInAccessGroup(order.BillingAddressID, UserGroupSuffix.ViewAllOrders.ToString(), decodedToken);

            if (isUserInLocationOrderAccessGroup)
            {
                return;
            }

            if (order.Status == OrderStatus.AwaitingApproval)
            {
                // logic assumes there is only one approving group per location
                var isUserInApprovalGroup = await _locationPermissionCommand.IsUserInAccessGroup(order.BillingAddressID, UserGroupSuffix.OrderApprover.ToString(), decodedToken);

                if (isUserInApprovalGroup)
                {
                    return;
                }
            }

            // if function has not been exited yet we throw an insufficient access error
            Require.That(false, new ErrorCode("Insufficient Access", 403, $"User cannot access order {order.ID}"));
        }
コード例 #15
0
        public async Task EnsureUserIsLocationAdmin(string locationID, DecodedToken decodedToken)
        {
            var hasAccess = await IsUserInAccessGroup(locationID, UserGroupSuffix.PermissionAdmin.ToString(), decodedToken);

            Require.That(hasAccess, new ErrorCode("Insufficient Access", 403, $"User cannot manage permissions for: {locationID}"));
        }
コード例 #16
0
        private async Task EnsureUserCanManageLocationResaleCert(string locationID, DecodedToken decodedToken)
        {
            var hasAccess = await _locationPermissionCommand.IsUserInAccessGroup(locationID, UserGroupSuffix.ResaleCertAdmin.ToString(), decodedToken);

            Require.That(hasAccess, new ErrorCode("Insufficient Access", 403, $"User cannot manage resale certs for: {locationID}"));
        }
コード例 #17
0
ファイル: OrderCommand.cs プロジェクト: kingeric027/headstart
        private async Task EnsureUserCanAccessLocationOrders(string locationID, DecodedToken decodedToken, string overrideErrorMessage = "")
        {
            var hasAccess = await _locationPermissionCommand.IsUserInAccessGroup(locationID, UserGroupSuffix.ViewAllOrders.ToString(), decodedToken);

            Require.That(hasAccess, new ErrorCode("Insufficient Access", 403, $"User cannot access orders from this location: {locationID}"));
        }