Esempio n. 1
0
    /// <summary>
    /// Check:: Booking Request expiration
    /// If::Provider didn't reply
    /// If::Request not updated/changed
    /// Action:: Set as expired, un-authorize/return money to customer, notify
    /// </summary>
    /// <param name="logger"></param>
    /// <param name="db"></param>
    /// <returns></returns>
    private static TaskResult RunBookingRequestExpiration(LcLogger logger, Database db)
    {
        var messages = 0L;
        var items    = 0L;

        foreach (var b in LcRest.Booking.QueryRequest2ExpiredBookings(db))
        {
            try
            {
                // RequestStatusID:6:expired
                b.ExpireBooking();
                // Send message
                LcMessaging.SendBooking.For(b.bookingID).BookingRequestExpired();
                // Update MessagingLog for the booking
                db.Execute(sqlAddBookingMessagingLog, b.bookingID, "[Booking Request Expiration]");

                items++;
                messages += 2;
            }
            catch (Exception ex)
            {
                logger.LogEx("Booking Request Expired", ex);
            }
        }
        logger.Log("Total invalidated as Expired Booking Requests: {0}, messages sent: {1}", items, messages);
        return(new TaskResult
        {
            ItemsProcessed = items,
            MessagesSent = messages
        });
    }
Esempio n. 2
0
    /// <summary>
    /// Saves on database the updated information for a payment account with the notified information that
    /// means an change on the payment gateway for that object.
    /// Braintree sends notifications through Webhooks to a configured URL, our page at that address
    /// manage it and call this when matched the Kind of notification related to the creation request
    /// for a Sub-merchant or Merchant account (aka provider payment account).
    /// </summary>
    /// <param name="notification"></param>
    public static void RegisterProviderPaymentAccountCreationNotification(WebhookNotification notification, string signature, string payload)
    {
        // If is not a SubMerchant creation, skip (maybe a new main merchant account was created)
        if (!notification.MerchantAccount.IsSubMerchant)
        {
            return;
        }

        var providerID = LcUtils.ExtractInt(notification.MerchantAccount.Id, 0);

        // Is not valid user
        if (providerID == 0)
        {
            using (var logger = new LcLogger("PaymentGatewayWebhook"))
            {
                logger.Log("SubMerchantAccount:: Impossible to get the provider UserID from next MerchantAccountID: {0}", notification.MerchantAccount.Id);
                logger.Log("SubMerchantAccount:: Follows signature and payload");
                logger.LogData(signature);
                logger.LogData(payload);
                logger.Save();
            }
            return;
        }

        LcData.SetProviderPaymentAccount(
            providerID,
            notification.MerchantAccount.Id,
            notification.MerchantAccount.Status.ToString(),
            notification.Message,
            signature,
            payload
            );
    }
        /// <summary>
        /// Check the due date of partnership plan subscriptions, setting them as expired is out of date.
        /// </summary>
        /// <param name="list"></param>
        /// <param name="logger"></param>
        private void EnforceDueDate(IEnumerable <LcRest.UserPaymentPlan> list, LcLogger logger)
        {
            long reviewed  = 0;
            long processed = 0;

            foreach (var userPlan in list)
            {
                try
                {
                    // CCCPlan subscriptions
                    if (userPlan.paymentPlan == LcEnum.SubscriptionPlan.CccPlan &&
                        userPlan.nextPaymentDueDate.HasValue)
                    {
                        reviewed++;
                        if (userPlan.nextPaymentDueDate.Value < DateTimeOffset.Now)
                        {
                            // Set as ended
                            userPlan.subscriptionEndDate = DateTimeOffset.Now;
                            // Set as expired, same value as Gateway/Braintree
                            userPlan.planStatus = Braintree.SubscriptionStatus.EXPIRED.ToString();
                            // Update DB
                            LcRest.UserPaymentPlan.Set(userPlan);
                            processed++;
                        }
                    }
                }
                catch (Exception ex)
                {
                    logger.LogEx("Check partnership subscriptions date for Past Due", ex);
                }
            }
            logger.Log("Partnership subscriptions updated because of Past Due: {0} from total reviewed {1}", processed, reviewed);
            ItemsReviewed  += reviewed;
            ItemsProcessed += processed;
        }
Esempio n. 4
0
    public static void LogAspnetError(Exception ex)
    {
        var Request = HttpContext.Current.Request;

        using (var logger = new LcLogger("aspnet-errors"))
        {
            try
            {
                logger.Log("Page error, unhandled exception caugth at Global.asax, context:");
                if (WebMatrix.WebData.WebSecurity.IsAuthenticated)
                {
                    logger.Log("User:: {0}:{1}", WebMatrix.WebData.WebSecurity.CurrentUserId, WebMatrix.WebData.WebSecurity.CurrentUserName);
                }
                else
                {
                    logger.Log("User:: Anonymous");
                }
                logger.Log("Request:: {0} {1}", Request.HttpMethod, Request.RawUrl);
                logger.Log("User-Agent:: {0}", Request.UserAgent);
                try
                {
                    logger.Log("Form Data::");
                    logger.LogData(ASP.LcHelpers.NameValueToString(Request.Form));
                }
                catch { }
                logger.LogEx("Page error details", ex);
            }
            catch { }
            logger.Save();
        }
    }
Esempio n. 5
0
        public static void Set(UserPaymentPlan data, LcDatabase sharedDb = null)
        {
            using (var db = new LcDatabase(sharedDb))
            {
                db.Execute(sqlSet,
                           data.userPaymentPlanID,
                           data.userID,
                           data.subscriptionID,
                           data.paymentPlan.ToString(),
                           data.paymentMethod,
                           data.paymentPlanLastChangedDate,
                           data.nextPaymentDueDate,
                           data.nextPaymentAmount,
                           data.firstBillingDate,
                           data.subscriptionEndDate,
                           data.paymentMethodToken,
                           data.paymentExpiryDate,
                           data.planStatus,
                           data.daysPastDue
                           );

                try
                {
                    // Set OwnerStatus
                    if (IsPartnershipPlan(data.paymentPlan))
                    {
                        var ow = new Owner();
                        ow.userID   = data.userID;
                        ow.statusID = (int)OwnerStatus.notYetAnOwner;
                        Owner.Set(ow);
                    }
                    else
                    {
                        // Run Membership Checks to enable/disable member (OwnerStatus update)
                        UserProfile.CheckAndSaveOwnerStatus(data.userID);
                    }
                }
                catch (Exception ex)
                {
                    // An error checking status must NOT prevent us from saving/creating
                    // the payment-plan, but we must notify staff so we can take manual action
                    // to fix the error and run the check again for this user
                    try
                    {
                        LcLogger.LogAspnetError(ex);
                        LcMessaging.NotifyError("UserPaymentPlan.Set->UserProfile.CheckAndSaveOwnerStatus::userID=" + data.userID,
                                                System.Web.HttpContext.Current.Request.RawUrl,
                                                ex.ToString());
                    }
                    catch
                    {
                        // Prevent cancel paymentplan creation/update because of email or log failing. Really strange
                        // and webhook-scheduleTask for subscriptions would attempt again this.
                    }
                }
            }
        }
Esempio n. 6
0
    /// <summary>
    /// Check:: Release Payment for Service Complete: 1 hour 15 min after service is performed
    /// (before #844 was 1 day after the service is performed)
    /// If:: Provider has already completed bookings (is not a new provider)
    /// If:: Performed bookings only, without pricing adjustment
    /// If:: Current time is 1 hour 15 min after Confirmed Service EndTime (before #844 was 1 day)
    /// Action:: set booking status as 'completed',
    /// send a messages.
    /// </summary>
    /// <param name="logger"></param>
    /// <param name="db"></param>
    /// <returns></returns>
    private static TaskResult RunBookingReleasePayment(LcLogger logger, Database db)
    {
        var messages = 0L;
        var items    = 0L;

        // NOTE: Changed to ALL providers at 2016-01-26 as of #844
        foreach (var b in LcRest.Booking.QueryPendingOfPaymentReleaseBookings(null, db))
        {
            try
            {
                // Release the payment
                try
                {
                    if (b.ReleasePayment())
                    {
                        items++;

                        // Send messages

                        // Notify customer and provider with an updated booking details:
                        LcMessaging.SendBooking.For(b.bookingID).BookingCompleted();

                        // Update MessagingLog for the booking
                        db.Execute(sqlAddBookingMessagingLog, b.bookingID, "[Release Payment 1H]");

                        messages += 2;
                    }
                }
                catch (Exception ex)
                {
                    var errTitle = "Booking Release Payment after 1H to providers";
                    var errDesc  = String.Format(
                        "BookingID: {0}, TransactionID: {1}. Not payed on [Release Payment 1H], error on Braintree 'release transaction from escrow': {2}",
                        b.bookingID,
                        b.paymentTransactionID,
                        ex.Message
                        );

                    LcMessaging.NotifyError(errTitle, "/ScheduleTask", errDesc);

                    logger.Log("Error on: " + errTitle + "; " + errDesc);
                }
            }
            catch (Exception ex)
            {
                logger.LogEx("Booking Release Payment 1H", ex);
            }
        }
        logger.Log("Total of Booking Release Payment after 1H: {0}, messages sent: {1}", items, messages);

        return(new TaskResult
        {
            ItemsProcessed = items,
            MessagesSent = messages
        });
    }
Esempio n. 7
0
    /// <summary>
    /// Check:: Setting No-Payment Bookings as Complete: 1 hour 15 min after service is performed
    /// If::Performed bookings only
    /// If:: Current time is 1 hour 15 min after Confirmed Service EndTime
    /// Action:: set booking status as 'completed',
    /// send messages.
    /// </summary>
    /// <param name="logger"></param>
    /// <param name="db"></param>
    /// <returns></returns>
    private static TaskResult RunBookingNoPaymentComplete(LcLogger logger, Database db)
    {
        var messages = 0L;
        var items    = 0L;

        foreach (var b in LcRest.Booking.QueryPendingOfCompleteWithoutPaymentBookings(db))
        {
            try
            {
                // Release the payment
                try
                {
                    b.SetBookingAsCompleted();
                    items++;

                    // Send messages

                    // Notify customer and provider with an updated booking details:
                    LcMessaging.SendBooking.For(b.bookingID).BookingCompleted();

                    // Update MessagingLog for the booking
                    db.Execute(sqlAddBookingMessagingLog, b.bookingID, "[Complete - no payment]");

                    messages += 2;
                }
                catch (Exception ex)
                {
                    var errTitle = "Setting No-Payment Bookings as Complete after 1H15M to providers";
                    var errDesc  = String.Format(
                        "BookingID: {0}, Error: {1}",
                        b.bookingID,
                        ex.Message
                        );

                    LcMessaging.NotifyError(errTitle, "/ScheduleTask", errDesc);

                    logger.Log("Error on: " + errTitle + "; " + errDesc);
                }
            }
            catch (Exception ex)
            {
                logger.LogEx("Setting No-Payment Bookings as Complete 1H15M", ex);
            }
        }
        logger.Log("Total of No-Payment Bookings set as Complete after 1H15M: {0}, messages sent: {1}", items, messages);

        return(new TaskResult
        {
            ItemsProcessed = items,
            MessagesSent = messages
        });
    }
        private void UpdateFromGateway(IEnumerable <LcRest.UserPaymentPlan> list, LcLogger logger)
        {
            long reviewed  = 0;
            long processed = 0;

            foreach (var userPlan in list)
            {
                try
                {
                    // Query Braintree subscription
                    var m    = new LcPayment.Membership();
                    var subs = m.GetSubscription(userPlan.subscriptionID);
                    reviewed++;

                    if (subs == null)
                    {
                        // Problem: saved ID didn't found at Braintree, corrupted data
                        var err = String.Format("Database subscriptionID '{0}' not found at Braintree, corrupted data." +
                                                " Please review user {1} subscription", userPlan.subscriptionID, userPlan.userID);
                        LcMessaging.NotifyError("UserPaymentPlanSubscriptionUpdatesTask", "ScheduledTask", err);
                        logger.Log(err);
                    }
                    else
                    {
                        // If status changed, update record
                        if (userPlan.planStatus != subs.Status.ToString())
                        {
                            userPlan.UpdatedAtGateway(subs);
                            LcRest.UserPaymentPlan.Set(userPlan);
                            // Update items count
                            processed++;

                            // Payments
                            foreach (var transaction in subs.Transactions)
                            {
                                var payment = LcRest.UserFeePayment.FromSubscriptionTransaction(userPlan, transaction);
                                LcRest.UserFeePayment.Set(payment);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    logger.LogEx("Pending and Past Due subscriptions", ex);
                }
            }
            logger.Log("Subscriptions updated from gateway: {0} from total reviewed {1}", processed, reviewed);
            ItemsReviewed  += reviewed;
            ItemsProcessed += processed;
        }
Esempio n. 9
0
    /// <summary>
    /// Check:: Authorize postponed transactions 24hours previous to service start-time
    /// If::Confirmed or performed bookings only, not cancelled or in dispute or completed(completed may be
    /// and old booking already paid
    /// If::Current time is 24 hours before Confirmed Service StartTime
    /// If:: BookingRequest PaymentTransactionID is a Card token rather than an actual TransactionID
    /// If::Customer was still not charged / transaction was not submitted for settlement ([ClientPayment] is null)
    /// Action::authorize booking transaction
    /// </summary>
    /// <param name="logger"></param>
    /// <param name="db"></param>
    /// <returns></returns>
    private static TaskResult RunBookingAuthorizePostponedTransactions(LcLogger logger, Database db)
    {
        var messages = 0L;
        var items    = 0L;

        foreach (var b in LcRest.Booking.QueryPostponedPaymentAuthorizations(db))
        {
            try
            {
                // Create transaction authorizing charge (but actually not charging still)
                // for saved customer credit card and update DB.
                try
                {
                    if (b.AuthorizeTransaction())
                    {
                        items++;
                    }
                }
                catch (Exception ex)
                {
                    var errTitle = "Booking Authorize Postponed Transactions, 24h before Service Starts";
                    var errDesc  = String.Format(
                        "BookingID: {0}, TransactionID: {1} Payment not allowed, error on Braintree 'sale transaction, authorizing only': {2}",
                        b.bookingID,
                        b.paymentTransactionID,
                        ex.Message
                        );

                    LcMessaging.NotifyError(errTitle, "/ScheduleTask", errDesc);

                    logger.Log("Error on: " + errTitle + "; " + errDesc);

                    // DOUBT: Notify providers on failed authorization/receive-payment?
                }
            }
            catch (Exception ex)
            {
                logger.LogEx("Booking Authorize Postponed Transactions, 24h before Service Starts", ex);
            }
        }
        logger.Log("Total of Booking Authorize Postponed Transactions, 24h before Service Starts: {0}", items);

        return(new TaskResult
        {
            ItemsProcessed = items,
            MessagesSent = messages
        });
    }
Esempio n. 10
0
        public static EarningsEntryReminderTask Run(LcLogger logger)
        {
            var task = new EarningsEntryReminderTask(logger);

            using (var db = new LcDatabase())
            {
                task.QueryUsers(db).All(task.ProcessUser);
            }

            task.TaskEnded = DateTime.Now;

            logger.Log("Elapsed time {0}, for {1} Earnings Entry Reminders sent, out of {2} records reviewed",
                       task.ElapsedTime, task.ItemsProcessed, task.ItemsReviewed);

            return(task);
        }
        public static UserPaymentPlanSubscriptionUpdatesTask Run(LcLogger logger)
        {
            var task = new UserPaymentPlanSubscriptionUpdatesTask();

            using (var db = new LcDatabase())
            {
                var list = LcRest.UserPaymentPlan.QueryActiveSubscriptions(db);
                task.UpdateFromGateway(list, logger);
            }

            task.TaskEnded = DateTime.Now;

            logger.Log("Elapsed time {0}, for {1} subscriptions processed, {2} records reviewed",
                       task.ElapsedTime, task.ItemsProcessed, task.ItemsReviewed);

            return(task);
        }
Esempio n. 12
0
    /// <summary>
    /// Check:: Charge Customer the day of the service
    /// If::Confirmated or performed bookings only, not cancelled or in dispute or completed(completed may be
    /// and old booking already paid
    /// If::Current time is the 1 hour after the End Service, or later
    /// If::Customer was still not charged / transaction was not submitted for settlement ([TotalPricePaidByCustomer] is null)
    /// Action::settle booking transaction
    /// set[TotalPricePaidByCustomer] and[TotalServiceFeesPaidByCustomer] values
    /// </summary>
    /// <param name="logger"></param>
    /// <param name="db"></param>
    /// <returns></returns>
    private static TaskResult RunBookingChargeCustomer(LcLogger logger, Database db)
    {
        var messages = 0L;
        var items    = 0L;

        // Get bookings affected by conditions
        foreach (var b in LcRest.Booking.QueryPendingOfClientChargeBookings(db))
        {
            try
            {
                // Charge customer and update DB
                try
                {
                    if (b.SettleTransaction())
                    {
                        items++;
                    }
                }
                catch (Exception ex)
                {
                    var errTitle = "Booking Charge Customer, Receive Payment";
                    var errDesc  = String.Format(
                        "BookingID: {0}, TransactionID: {1} Payment not received, error on Braintree 'settle transaction': {2}",
                        b.bookingID,
                        b.paymentTransactionID,
                        ex.Message
                        );

                    LcMessaging.NotifyError(errTitle, "/ScheduleTask", errDesc);

                    logger.Log("Error on: " + errTitle + "; " + errDesc);
                }
            }
            catch (Exception ex)
            {
                logger.LogEx("Booking Charge Customer, Receive Payment", ex);
            }
        }
        logger.Log("Total of Booking Charge Customer, Receive Payment: {0}", items);

        return(new TaskResult
        {
            ItemsProcessed = items,
            MessagesSent = messages
        });
    }
Esempio n. 13
0
    /// <summary>
    /// Check:: [48H Service Reminder] Booking will be on 48Hours
    /// If::Confirmated bookings not cancelled
    /// If::Current time is 48 hours before Confirmed Service StarTime
    /// Action:: send a booking reminder email
    /// </summary>
    /// <param name="logger"></param>
    /// <param name="db"></param>
    /// <returns></returns>
    private static TaskResult RunBooking48HReminder(LcLogger logger, Database db)
    {
        var messages = 0L;
        var items    = 0L;

        foreach (var b in db.Query(@"
                SELECT  BookingID
                FROM    Booking As B
                         INNER JOIN
                        CalendarEvents As E
                          ON B.ServiceDateID = E.Id
                WHERE   BookingStatusID = @0
                         AND
                        -- at 48 hours before service starts (between 49 and 48 hours)
                        getdate() > dateadd(hh, -49, E.StartTime)
                         AND
                        getdate() <= dateadd(hh, -48, E.StartTime)
                         AND
                        B.MessagingLog not like '%[48H Service Reminder]%'
            ", (int)LcEnum.BookingStatus.confirmed))
        {
            try
            {
                // Send message
                LcMessaging.SendBooking.For(b.BookingID).BookingReminder();

                // Update MessagingLog for the booking
                db.Execute(sqlAddBookingMessagingLog, b.BookingID, "[48H Service Reminder]");

                items++;
                messages += 2;
            }
            catch (Exception ex)
            {
                logger.LogEx("Booking 48H Reminders", ex);
            }
        }
        logger.Log("Total of Booking 48H Reminders: {0}, messages sent: {1}", items, messages);

        return(new TaskResult
        {
            ItemsProcessed = items,
            MessagesSent = messages
        });
    }
        public static UserPaymentPlanSubscriptionUpdatesTask Run(LcLogger logger)
        {
            var task = new UserPaymentPlanSubscriptionUpdatesTask();

            using (var db = new LcDatabase())
            {
                // Subcriptions that need udpate from Gateway
                var list = LcRest.UserPaymentPlan.QueryActiveSubscriptions(true, db);
                task.UpdateFromGateway(list, logger);
                // No-payment subscriptions, currently just partnership plans, that need manual check of due date
                task.EnforceDueDate(LcRest.UserPaymentPlan.QueryActiveSubscriptions(false, db), logger);
            }

            task.TaskEnded = DateTime.Now;

            logger.Log("Elapsed time {0}, for {1} subscriptions processed, {2} records reviewed",
                       task.ElapsedTime, task.ItemsProcessed, task.ItemsReviewed);

            return(task);
        }
Esempio n. 15
0
    private static void RunIcalendar(LcLogger logger)
    {
        DateTime partialElapsedTime = DateTime.Now;

        int successCalendars = 0,
            failedCalendars  = 0;

        foreach (var err in LcCalendar.BulkImport())
        {
            if (err == null)
            {
                successCalendars++;
            }
            else
            {
                failedCalendars++;
                logger.LogEx("Import Calendar", err);
            }
        }

        logger.Log("Elapsed time {0}, for {1} user calendars imported, {2} failed", DateTime.Now - partialElapsedTime, successCalendars, failedCalendars);
    }
Esempio n. 16
0
    /// <summary>
    /// Check:: Booking timed out
    /// If::A not complete booking request exist without changes from more than 1 day
    /// Action:: Invalidate the booking tentative events
    /// </summary>
    /// <param name="logger"></param>
    /// <param name="db"></param>
    /// <returns></returns>
    private static TaskResult RunBookingTimedOut(LcLogger logger, Database db)
    {
        var items = 0L;

        foreach (var b in LcRest.Booking.QueryIncomplete2TimedoutBookings(db))
        {
            try
            {
                LcRest.Booking.SetAsTimedout(b, db);
                items++;
            }
            catch (Exception ex)
            {
                logger.LogEx("Booking Timed-out", ex);
            }
        }
        logger.Log("Total invalidated as TimedOut Booking: {0}, messages sent: {1}", items, 0);
        return(new TaskResult
        {
            ItemsProcessed = items
        });
    }
Esempio n. 17
0
    /// <summary>
    /// Check:: Service Performed: The end of the service (before #844, was at 48H passed from Service)
    /// If::Confirmated bookings only, not cancelled, not set as performed, complete or dispute
    /// If:: Current time is Confirmed Service EndTime
    /// Action:: set booking status as 'service-performed'
    /// </summary>
    /// <param name="logger"></param>
    /// <param name="db"></param>
    /// <returns></returns>
    private static TaskResult RunBookingServicePerformed(LcLogger logger, Database db)
    {
        var messages = 0L;
        var items    = 0L;

        foreach (var b in LcRest.Booking.QueryConfirmed2ServicePerformedBookings(db))
        {
            try
            {
                // Set as servicePerformed
                b.bookingStatusID = (int)LcEnum.BookingStatus.servicePerformed;
                LcRest.Booking.SetStatus(b, db);

                // Send messages

                // Notify customer and provider with an updated booking details:
                LcMessaging.SendBooking.For(b.bookingID).ServicePerformed();

                // Update MessagingLog for the booking
                db.Execute(sqlAddBookingMessagingLog, b.bookingID, "[Service Performed]");

                items++;
                // Before Marketplace: messages += 3;
                messages += 2;
            }
            catch (Exception ex)
            {
                logger.LogEx("Booking Service Performed", ex);
            }
        }
        logger.Log("Total of Booking Service Performed: {0}, messages sent: {1}", items, messages);

        return(new TaskResult
        {
            ItemsProcessed = items,
            MessagesSent = messages
        });
    }
Esempio n. 18
0
    /// <summary>
    /// Performs a transaction to authorize the payment on the client payment method, but
    /// not charging still, using the data from the given booking and the saved paymentMethodID.
    /// Booking is NOT checked before perform the task, use the LcRest.Booking API to securely run pre-condition
    /// checks before authorize transaction. The booking must have the data loaded for the pricingSummary.
    ///
    /// REVIEWED #771
    /// </summary>
    /// <param name="booking"></param>
    /// <param name="paymentMethodID">AKA creditCardToken</param>
    /// <returns>It returns the transactionID generated, original booking object is not updated.
    /// Errors in the process are throwed.</returns>
    public static string AuthorizeBookingTransaction(LcRest.Booking booking)
    {
        if (booking.pricingSummary == null ||
            !booking.pricingSummary.totalPrice.HasValue ||
            booking.pricingSummary.totalPrice.Value <= 0)
        {
            throw new ConstraintException("To authorize a booking payment is required a price to charge.");
        }

        var gateway = NewBraintreeGateway();

        TransactionRequest request = new TransactionRequest
        {
            Amount = booking.pricingSummary.totalPrice.Value,
            // Marketplace #408: since provider receive the money directly, Braintree must discount
            // the next amount in concept of fees and pay that to the Marketplace Owner (us, Loconomics ;-)
            ServiceFeeAmount   = booking.pricingSummary.serviceFeeAmount,
            CustomerId         = GetCustomerId(booking.clientUserID),
            PaymentMethodToken = booking.paymentMethodID,
            // Now, with Marketplace #408, the receiver of the money for each transaction is
            // the provider through account at Braintree, and not the Loconomics account:
            //MerchantAccountId = LcPayment.BraintreeMerchantAccountId,
            MerchantAccountId = GetProviderPaymentAccountId(booking.serviceProfessionalUserID),
            Options           = new TransactionOptionsRequest
            {
                // Marketplace #408: don't pay provider still, wait for the final confirmation 'release scrow'
                HoldInEscrow = true,
                // Do not submit, just authorize:
                SubmitForSettlement = false
            }
        };

        var r = gateway.Transaction.Sale(request);

        // Everything goes fine
        if (r.IsSuccess())
        {
            // Get the transactionID
            if (r.Target != null &&
                !String.IsNullOrEmpty(r.Target.Id))
            {
                // If the card is a TEMPorarly card (just to perform this transaction)
                // it must be removed now since was successful used
                // IMPORTANT: Since an error on this subtask is not important to the
                // user and will break a success process creating a new problem if throwed (because transactionID
                // gets lost),
                // is catched and managed internally by Loconomics stuff that can check and fix transparentely
                // this minor error.
                try
                {
                    if (booking.paymentMethodID.StartsWith(TempSavedCardPrefix))
                    {
                        gateway.CreditCard.Delete(booking.paymentMethodID);
                    }
                }
                catch (Exception ex)
                {
                    try
                    {
                        LcMessaging.NotifyError(String.Format("LcPayment.AuthorizeBookingTransaction..DeleteBraintreeTempCard({0});bookingID={1}", booking.paymentMethodID, booking.bookingID), "", ex.Message);
                        LcLogger.LogAspnetError(ex);
                    }
                    catch { }
                }

                // r.Target.Id => transactionID
                return(r.Target.Id);
            }
            else
            {
                // Transaction worked but impossible to know the transactionID (weird, is even possible?),
                // notify error
                throw new Exception("Impossible to know transaction details, please contact support. BookingID #" + booking.bookingID.ToString());
            }
        }
        else
        {
            throw new Exception(r.Message);
        }
    }
Esempio n. 19
0
    /// <summary>
    /// Runs all tasks if the conditions for each are met.
    /// </summary>
    /// <returns>Logged string</returns>
    public static string Run()
    {
        var logger      = new LcLogger("ScheduledTask");
        var elapsedTime = DateTime.Now;

        /*
         * Bookings
         */
        var        totalmessages = 0L;
        var        totalitems    = 0L;
        TaskResult result;
        var        taskRunners = new List <BookingTaskRunner>
        {
            RunBookingTimedOut,
            RunBookingRequestExpiration,
            RunBooking48HReminder,
            RunBookingAuthorizePostponedTransactions,
            RunBookingChargeCustomer,
            RunBookingServicePerformed,
            RunBookingReleasePayment,
            RunBookingNoPaymentComplete,
            RunBookingReviewReminder1W
        };

        using (var db = Database.Open("sqlloco"))
        {
            foreach (var runner in taskRunners)
            {
                try
                {
                    result         = runner(logger, db);
                    totalitems    += result.ItemsProcessed;
                    totalmessages += result.MessagesSent;
                }
                catch (Exception ex)
                {
                    logger.LogEx(runner.Method.Name, ex);
                }
            }
            // Ending work with database
        }

        logger.Log("Elapsed time {0}, for {1} bookings affected and {2} messages sent", DateTime.Now - elapsedTime, totalitems, totalmessages);


        /*
         * iCalendar
         */
        try
        {
            RunIcalendar(logger);
        }
        catch (Exception err)
        {
            logger.LogEx("Import Calendar", err);
        }

        /*
         * Membership tasks
         */
        // Note: the whole ScheduleTask is set-up to run every hour,
        // since the subscriptions status is keep up to date by Webhooks already,
        // and this task is just a fallback in case of communication error and can
        // perform lot of request to Braintree, we force to reduce execution to once
        // a week.
        // Easily, we just check if we are at Midnight of Monday
        if (DateTime.Now.Hour == 0 && DateTime.Now.DayOfWeek == DayOfWeek.Monday)
        {
            try
            {
                Tasks.UserPaymentPlanSubscriptionUpdatesTask.Run(logger);
            }
            catch (Exception err)
            {
                logger.LogEx("UserPaymentPlanSubscriptionUpdatesTask", err);
            }
        }

        // Earnings reminder are sent only two times a month, so we check the day and the hour
        // (the hour to make it just once at the matched day, since the task executes every hour)
        if ((DateTime.Now.Day == 1 || DateTime.Now.Day == 15) && DateTime.Now.Hour == 7)
        {
            try
            {
                Tasks.EarningsEntryReminderTask.Run(logger);
            }
            catch (Exception err)
            {
                logger.LogEx("EarningsEntryReminderTask", err);
            }
        }

        /*
         * Task Ended
         */
        logger.Log("Total Elapsed time {0}", DateTime.Now - elapsedTime);

        string logresult = logger.ToString();

        // Finishing: save log on disk, per month rotation
        //try {
        logger.Save();
        // Send Email too if exceptions found
        if (logger.HasExceptions)
        {
            LcMessaging.NotifyError("ScheduleTask throw Exceptions", "/ScheduledTask", logresult);
        }
        //}catch { }

        return(logresult);
    }
Esempio n. 20
0
    /// <summary>
    /// Runs all tasks if the conditions for each are met.
    /// </summary>
    /// <returns>Logged string</returns>
    public static string Run()
    {
        var logger      = new LcLogger("ScheduledTask");
        var elapsedTime = DateTime.Now;

        /*
         * Bookings
         */

        int messages = 0, items = 0;
        int totalmessages = 0, totalitems = 0;

        var sqlAddBookingMessagingLog = "UPDATE Booking SET MessagingLog = coalesce(MessagingLog, '') + @1 WHERE BookingID=@0";

        using (var db = Database.Open("sqlloco"))
        {
            /*
             * Check:: Booking timed out
             * If:: A not complete booking request exist without changes from more than 1 day
             * Action:: Invalidate the booking tentative events
             */
            messages = 0;
            items    = 0;
            foreach (var b in LcRest.Booking.QueryIncomplete2TimedoutBookings(db))
            {
                try
                {
                    LcRest.Booking.SetAsTimedout(b, db);
                    items++;
                }
                catch (Exception ex)
                {
                    logger.LogEx("Booking Timed-out", ex);
                }
            }
            logger.Log("Total invalidated as TimedOut Booking: {0}, messages sent: {1}", items, messages);
            totalitems    += items;
            totalmessages += messages;

            /*
             * Check:: Booking Request expiration
             * If:: Provider didn't reply
             * If:: Request not updated/changed
             * Action:: Set as expired, un-authorize/return money to customer, notify
             */
            messages = 0;
            items    = 0;
            foreach (var b in LcRest.Booking.QueryRequest2ExpiredBookings(db))
            {
                try
                {
                    // RequestStatusID:6:expired
                    b.ExpireBooking();
                    // Send message
                    LcMessaging.SendBooking.For(b.bookingID).BookingRequestExpired();
                    // Update MessagingLog for the booking
                    db.Execute(sqlAddBookingMessagingLog, b.bookingID, "[Booking Request Expiration]");

                    items++;
                    messages += 2;
                }
                catch (Exception ex)
                {
                    logger.LogEx("Booking Request Expired", ex);
                }
            }
            logger.Log("Total invalidated as Expired Booking Requests: {0}, messages sent: {1}", items, messages);
            totalitems    += items;
            totalmessages += messages;

            /*
             * Check:: [48H Service Reminder] Booking will be on 48Hours
             * If:: Confirmated bookings not cancelled
             * If:: Current time is 48 hours before Confirmed Service StarTime
             * Action:: send a booking reminder email
             */
            messages = 0;
            items    = 0;
            foreach (var b in db.Query(@"
                SELECT  BookingID
                FROM    Booking As B
                         INNER JOIN
                        CalendarEvents As E
                          ON B.ServiceDateID = E.Id
                WHERE   BookingStatusID = @0
                         AND
                        -- at 48 hours before service starts (between 49 and 48 hours)
                        getdate() > dateadd(hh, -49, E.StartTime)
                         AND
                        getdate() <= dateadd(hh, -48, E.StartTime)
                         AND
                        B.MessagingLog not like '%[48H Service Reminder]%'
            ", (int)LcEnum.BookingStatus.confirmed))
            {
                try
                {
                    // Send message
                    LcMessaging.SendBooking.For(b.BookingID).BookingReminder();

                    // Update MessagingLog for the booking
                    db.Execute(sqlAddBookingMessagingLog, b.BookingID, "[48H Service Reminder]");

                    items++;
                    messages += 2;
                }
                catch (Exception ex)
                {
                    logger.LogEx("Booking 48H Reminders", ex);
                }
            }
            logger.Log("Total of Booking 48H Reminders: {0}, messages sent: {1}", items, messages);
            totalitems    += items;
            totalmessages += messages;

            /*
             * Check:: Authorize postponed transactions 24hours previous to service start-time
             * If:: Confirmed or performed bookings only, not cancelled or in dispute or completed (completed may be
             * and old booking already paid
             * If:: Current time is 24 hours before Confirmed Service StartTime
             * If:: BookingRequest PaymentTransactionID is a Card token rather than an actual TransactionID
             * If:: Customer was still not charged / transaction was not submitted for settlement ([ClientPayment] is null)
             * Action:: authorize booking transaction
             */
            items = 0;
            {
                foreach (var b in LcRest.Booking.QueryPostponedPaymentAuthorizations(db))
                {
                    try
                    {
                        // Create transaction authorizing charge (but actually not charging still)
                        // for saved customer credit card and update DB.
                        try
                        {
                            if (b.AuthorizeTransaction())
                            {
                                items++;
                            }
                        }
                        catch (Exception ex)
                        {
                            var errTitle = "Booking Authorize Postponed Transactions, 24h before Service Starts";
                            var errDesc  = String.Format(
                                "BookingID: {0}, TransactionID: {1} Payment not allowed, error on Braintree 'sale transaction, authorizing only': {2}",
                                b.bookingID,
                                b.paymentTransactionID,
                                ex.Message
                                );

                            LcMessaging.NotifyError(errTitle, "/ScheduleTask", errDesc);

                            logger.Log("Error on: " + errTitle + "; " + errDesc);

                            // DOUBT: Notify providers on failed authorization/receive-payment?
                        }
                    }
                    catch (Exception ex)
                    {
                        logger.LogEx("Booking Authorize Postponed Transactions, 24h before Service Starts", ex);
                    }
                }
            }
            logger.Log("Total of Booking Authorize Postponed Transactions, 24h before Service Starts: {0}", items);
            totalitems += items;

            /*
             * Check:: Charge Customer the day of the service
             * If:: Confirmated or performed bookings only, not cancelled or in dispute or completed (completed may be
             * and old booking already paid
             * If:: Current time is the 1 hour after the End Service, or later
             * If:: Customer was still not charged / transaction was not submitted for settlement ([TotalPricePaidByCustomer] is null)
             * Action:: settle booking transaction
             *          set [TotalPricePaidByCustomer] and [TotalServiceFeesPaidByCustomer] values
             */
            items = 0;
            {
                // Get bookings affected by conditions

                foreach (var b in LcRest.Booking.QueryPendingOfClientChargeBookings(db))
                {
                    try
                    {
                        // Charge customer and update DB
                        try
                        {
                            if (b.SettleTransaction())
                            {
                                items++;
                            }
                        }
                        catch (Exception ex)
                        {
                            var errTitle = "Booking Charge Customer, Receive Payment";
                            var errDesc  = String.Format(
                                "BookingID: {0}, TransactionID: {1} Payment not received, error on Braintree 'settle transaction': {2}",
                                b.bookingID,
                                b.paymentTransactionID,
                                ex.Message
                                );

                            LcMessaging.NotifyError(errTitle, "/ScheduleTask", errDesc);

                            logger.Log("Error on: " + errTitle + "; " + errDesc);
                        }
                    }
                    catch (Exception ex)
                    {
                        logger.LogEx("Booking Charge Customer, Receive Payment", ex);
                    }
                }
            }
            logger.Log("Total of Booking Charge Customer, Receive Payment: {0}", items);
            totalitems += items;

            /*
             * Check:: Service Performed: The end of the service (before #844, was at 48H passed from Service)
             * If:: Confirmated bookings only, not cancelled, not set as performed, complete or dispute
             * If:: Current time is Confirmed Service EndTime
             * Action:: set booking status as 'service-performed'
             */
            messages = 0;
            items    = 0;
            {
                foreach (var b in LcRest.Booking.QueryConfirmed2ServicePerformedBookings(db))
                {
                    try
                    {
                        // Set as servicePerformed
                        b.bookingStatusID = (int)LcEnum.BookingStatus.servicePerformed;
                        LcRest.Booking.SetStatus(b, db);

                        // Send messages

                        // Notify customer and provider with an updated booking details:
                        LcMessaging.SendBooking.For(b.bookingID).ServicePerformed();

                        // Update MessagingLog for the booking
                        db.Execute(sqlAddBookingMessagingLog, b.bookingID, "[Service Performed]");

                        items++;
                        // Before Marketplace: messages += 3;
                        messages += 2;
                    }
                    catch (Exception ex)
                    {
                        logger.LogEx("Booking Service Performed", ex);
                    }
                }
            }
            logger.Log("Total of Booking Service Performed: {0}, messages sent: {1}", items, messages);
            totalitems    += items;
            totalmessages += messages;

            /*
             * Check:: Release Payment for New Providers: 5 full days after the service is performed
             * If:: If provider is a new provider (it has not previous completed bookings)
             * If:: Performed bookings only, without pricing adjustment
             * If:: Current time is 5 days after Confirmed Service EndTime
             * Action:: set booking status as 'completed',
             *          send a message to the provider notifying that payment is released.
             */
            /* REMOVED AS OF #844, 2016-01-26
             * messages = 0;
             * items = 0;
             * {
             *  foreach (var b in LcRest.Booking.QueryPendingOfPaymentReleaseBookings(true, db))
             *  {
             *      try
             *      {
             *          // Release the payment
             *          try
             *          {
             *              if (b.ReleasePayment())
             *              {
             *                  items++;
             *
             *                  // Send messages
             *
             *                  // Notify customer and provider with an updated booking details:
             *                  LcMessaging.SendBooking.For(b.bookingID).BookingCompleted();
             *
             *                  // Update MessagingLog for the booking
             *                  db.Execute(sqlAddBookingMessagingLog, b.bookingID, "[Release Payment 120H New Provider]");
             *
             *                  messages += 2;
             *              }
             *          }
             *          catch (Exception ex)
             *          {
             *
             *              var errTitle = "Booking Release Payment after 120H for new providers";
             *              var errDesc = String.Format(
             *                  "BookingID: {0}, TransactionID: {1}. Not payed on [Release Payment 120H New Provider], error on Braintree 'release transaction from escrow': {2}",
             *                  b.bookingID,
             *                  b.paymentTransactionID,
             *                  ex.Message
             *              );
             *
             *              LcMessaging.NotifyError(errTitle, "/ScheduleTask", errDesc);
             *
             *              logger.Log("Error on: " + errTitle + "; " + errDesc);
             *          }
             *      }
             *      catch (Exception ex)
             *      {
             *          logger.LogEx("Booking Release Payment after 120H for new providers", ex);
             *      }
             *  }
             * }
             * logger.Log("Total of Booking Release Payment after 120H for new providers: {0}, messages sent: {1}", items, messages);
             * totalitems += items;
             * totalmessages += messages;
             */

            /*
             * Check:: Release Payment for Service Complete: 1 hour 15 min after service is performed
             * (before #844 was 1 day after the service is performed)
             * //If:: Provider has already completed bookings (is not a new provider)
             * If:: Performed bookings only, without pricing adjustment
             * If:: Current time is 1 hour 15 min after Confirmed Service EndTime (before #844 was 1 day)
             * Action:: set booking status as 'completed',
             *          send a messages.
             */
            messages = 0;
            items    = 0;
            {
                // NOTE: Changed to ALL providers at 2016-01-26 as of #844
                foreach (var b in LcRest.Booking.QueryPendingOfPaymentReleaseBookings(null, db))
                {
                    try
                    {
                        // Release the payment
                        try
                        {
                            if (b.ReleasePayment())
                            {
                                items++;

                                // Send messages

                                // Notify customer and provider with an updated booking details:
                                LcMessaging.SendBooking.For(b.bookingID).BookingCompleted();

                                // Update MessagingLog for the booking
                                db.Execute(sqlAddBookingMessagingLog, b.bookingID, "[Release Payment 1H]");

                                messages += 2;
                            }
                        }
                        catch (Exception ex)
                        {
                            var errTitle = "Booking Release Payment after 1H to providers";
                            var errDesc  = String.Format(
                                "BookingID: {0}, TransactionID: {1}. Not payed on [Release Payment 1H], error on Braintree 'release transaction from escrow': {2}",
                                b.bookingID,
                                b.paymentTransactionID,
                                ex.Message
                                );

                            LcMessaging.NotifyError(errTitle, "/ScheduleTask", errDesc);

                            logger.Log("Error on: " + errTitle + "; " + errDesc);
                        }
                    }
                    catch (Exception ex)
                    {
                        logger.LogEx("Booking Release Payment 1H", ex);
                    }
                }
            }
            logger.Log("Total of Booking Release Payment after 1H: {0}, messages sent: {1}", items, messages);
            totalitems    += items;
            totalmessages += messages;

            /*
             * Check:: Setting No-Payment Bookings as Complete: 1 hour 15 min after service is performed
             * If:: Performed bookings only
             * If:: Current time is 1 hour 15 min after Confirmed Service EndTime
             * Action:: set booking status as 'completed',
             *          send messages.
             */
            messages = 0;
            items    = 0;
            {
                foreach (var b in LcRest.Booking.QueryPendingOfCompleteWithoutPaymentBookings(db))
                {
                    try
                    {
                        // Release the payment
                        try
                        {
                            b.SetBookingAsCompleted();
                            items++;

                            // Send messages

                            // Notify customer and provider with an updated booking details:
                            LcMessaging.SendBooking.For(b.bookingID).BookingCompleted();

                            // Update MessagingLog for the booking
                            db.Execute(sqlAddBookingMessagingLog, b.bookingID, "[Complete - no payment]");

                            messages += 2;
                        }
                        catch (Exception ex)
                        {
                            var errTitle = "Setting No-Payment Bookings as Complete after 1H15M to providers";
                            var errDesc  = String.Format(
                                "BookingID: {0}, Error: {1}",
                                b.bookingID,
                                ex.Message
                                );

                            LcMessaging.NotifyError(errTitle, "/ScheduleTask", errDesc);

                            logger.Log("Error on: " + errTitle + "; " + errDesc);
                        }
                    }
                    catch (Exception ex)
                    {
                        logger.LogEx("Setting No-Payment Bookings as Complete 1H15M", ex);
                    }
                }
            }
            logger.Log("Total of No-Payment Bookings set as Complete after 1H15M: {0}, messages sent: {1}", items, messages);
            totalitems    += items;
            totalmessages += messages;


            /*
             * Check:: [8AM Review Reminder] Booking Review Reminder Next day after service at 8AM
             * If:: Confirmed bookings not cancelled
             * If:: User did not the review still
             * If:: Current time is 8AM on the day after the Confirmed Service EndTime
             * Action:: send a booking review reminder email
             */
            /* DISABLED AS OF #844, 2016-01-26. Reminder information goes into the 'completed' email that happens sooner than before
             * messages = 0;
             * items = 0;
             * var confirmedPerformedCompletedStatuses = String.Join(",", new List<int> { (int)LcEnum.BookingStatus.confirmed, (int)LcEnum.BookingStatus.servicePerformed, (int)LcEnum.BookingStatus.completed });
             * foreach (var b in db.Query(@"
             *  SELECT  B.BookingID,
             *          CAST(CASE WHEN (SELECT count(*) FROM UserReviews As URP
             *              WHERE URP.BookingID = B.BookingID
             *                  AND
             *                  URP.ProviderUserID = B.ServiceProfessionalUserID
             *                  AND
             *                  URP.PositionID = 0
             *          ) = 0 THEN 0 ELSE 1 END As bit) As ReviewedByProvider,
             *          CAST(CASE WHEN (SELECT count(*) FROM UserReviews As URC
             *              WHERE URC.BookingID = B.BookingID
             *                  AND
             *                  URC.CustomerUserID = B.ClientUserID
             *                  AND
             *                  URC.PositionID = B.JobTitleID
             *          ) = 0 THEN 0 ELSE 1 END As bit) As ReviewedByCustomer
             *  FROM    Booking As B
             *           INNER JOIN
             *          CalendarEvents As E
             *            ON B.ServiceDateID = E.Id
             *  WHERE   B.BookingStatusID  IN (" + String.Join(",", new List<int> { (int)LcEnum.BookingStatus.confirmed, (int)LcEnum.BookingStatus.servicePerformed, (int)LcEnum.BookingStatus.completed }) + @")
             *           AND
             *          -- at 8AM hours
             *          datepart(hh, getdate()) = 8
             *           AND
             *          -- of the day after the service
             *          Cast(dateadd(d, -1, getdate()) As Date) = Cast(E.EndTime As Date)
             *           AND
             *          B.MessagingLog not like '%[8AM Review Reminder]%'
             * "))
             * {
             *  try
             *  {
             *      // We need check that there was not reviews already (why send a reminder for something
             *      // already done? just we avoid that!).
             *      // If both users did its reviews, nothing to send
             *      if (b.ReviewedByProvider && b.ReviewedByCustomer)
             *      {
             *          // Next booking
             *          continue;
             *      }
             *      char messageFor =
             *          b.ReviewedByProvider ? 'c' :
             *          b.ReviewedByCustomer ? 'p' :
             *          'b';
             *
             *      // Send message
             *      LcMessaging.SendBooking.For((int)b.BookingID).RequestToReview();
             *
             *      // Update MessagingLog for the booking
             *      db.Execute(sqlAddBookingMessagingLog, b.BookingID, "[8AM Review Reminder]");
             *
             *      items++;
             *      if (messageFor == 'c' || messageFor == 'p')
             *      {
             *          messages++;
             *      }
             *      else
             *      {
             *          messages += 2;
             *      }
             *  }
             *  catch (Exception ex)
             *  {
             *      logger.LogEx("Booking Review Reminders Next 8AM", ex);
             *  }
             * }
             * logger.Log("Total of Booking Review Reminders Next 8AM: {0}, messages sent: {1}", items, messages);
             * totalitems += items;
             * totalmessages += messages;
             */

            /*
             * Check:: [1W Review Reminder] Booking Review Reminder 1Week after service
             * If:: Confirmed bookings not cancelled, non stoped manully, maybe is set as performed already
             * If:: User did not the review still
             * If:: Past 1 Week from service
             * Action:: send a booking review reminder email
             */
            messages = 0;
            items    = 0;
            foreach (var b in db.Query(@"
                SELECT  B.BookingID,
                        CAST(CASE WHEN (SELECT count(*) FROM UserReviews As URP
                            WHERE URP.BookingID = B.BookingID
                                AND
                                URP.ProviderUserID = B.ServiceProfessionalUserID
                                AND 
                                URP.PositionID = 0
                        ) = 0 THEN 0 ELSE 1 END As bit) As ReviewedByProvider,
                        CAST(CASE WHEN (SELECT count(*) FROM UserReviews As URC
                            WHERE URC.BookingID = B.BookingID
                                AND
                                URC.CustomerUserID = B.ClientUserID
                                AND 
                                URC.PositionID = B.JobTitleID
                        ) = 0 THEN 0 ELSE 1 END As bit) As ReviewedByCustomer
                FROM    Booking As B
                         INNER JOIN
                        CalendarEvents As E
                          ON B.ServiceDateID = E.Id
                WHERE   B.BookingStatusID IN (" +
                                       String.Join(",", new List <int> {
                (int)LcEnum.BookingStatus.confirmed, (int)LcEnum.BookingStatus.servicePerformed, (int)LcEnum.BookingStatus.completed
            }) + @")
                         AND
                        -- at 1 Week=168 hours, after service ended (between 168 and 175 hours -6 hours of margin-)
                        getdate() >= dateadd(hh, 168, E.EndTime)
                         AND
                        getdate() < dateadd(hh, 175, E.EndTime)
                         AND
                        B.MessagingLog not like '%[1W Review Reminder]%'
            "))
            {
                try
                {
                    // We need check that there was not reviews already (why send a reminder for something
                    // already done? just we avoid that!).
                    // If both users did its reviews, nothing to send
                    if (b.ReviewedByProvider && b.ReviewedByCustomer)
                    {
                        // Next booking
                        continue;
                    }
                    char messageFor =
                        b.ReviewedByProvider ? 'c' :
                        b.ReviewedByCustomer ? 'p' :
                        'b';

                    // Send message
                    LcMessaging.SendBooking.For((int)b.BookingID).RequestToReviewReminder();

                    // Update MessagingLog for the booking
                    db.Execute(sqlAddBookingMessagingLog, b.BookingID, "[1W Review Reminder]");

                    items++;
                    if (messageFor == 'c' || messageFor == 'p')
                    {
                        messages++;
                    }
                    else
                    {
                        messages += 2;
                    }
                }
                catch (Exception ex)
                {
                    logger.LogEx("Booking Review Reminders 1W", ex);
                }
            }
            logger.Log("Total of Booking Review Reminders 1W: {0}, messages sent: {1}", items, messages);
            totalitems    += items;
            totalmessages += messages;

            // Ending work with database
        }

        logger.Log("Elapsed time {0}, for {1} bookings affected and {2} messages sent", DateTime.Now - elapsedTime, totalitems, totalmessages);


        /*
         * iCalendar
         */
        DateTime partialElapsedTime = DateTime.Now;

        int successCalendars = 0,
            failedCalendars  = 0;

        foreach (var err in LcCalendar.BulkImport())
        {
            if (err == null)
            {
                successCalendars++;
            }
            else
            {
                failedCalendars++;
                logger.LogEx("Import Calendar", err);
            }
        }

        logger.Log("Elapsed time {0}, for {1} user calendars imported, {2} failed", DateTime.Now - partialElapsedTime, successCalendars, failedCalendars);


        /*
         * Task Ended
         */
        logger.Log("Total Elapsed time {0}", DateTime.Now - elapsedTime);

        string logresult = logger.ToString();

        // Finishing: save log on disk, per month rotation
        //try {
        logger.Save();
        //}catch { }

        return(logresult);
    }
Esempio n. 21
0
    /// <summary>
    /// Check:: [1W Review Reminder] Booking Review Reminder 1Week after service
    /// If::Confirmed bookings not cancelled, non stoped manully, maybe is set as performed already
    /// If::User did not the review still
    /// If::Past 1 Week from service
    /// Action:: send a booking review reminder email
    /// </summary>
    /// <param name="logger"></param>
    /// <param name="db"></param>
    /// <returns></returns>
    private static TaskResult RunBookingReviewReminder1W(LcLogger logger, Database db)
    {
        var messages = 0L;
        var items    = 0L;

        foreach (var b in db.Query(@"
                SELECT  B.BookingID,
                        CAST(CASE WHEN (SELECT count(*) FROM UserReviews As URP
                            WHERE URP.BookingID = B.BookingID
                                AND
                                URP.ProviderUserID = B.ServiceProfessionalUserID
                                AND 
                                URP.PositionID = 0
                        ) = 0 THEN 0 ELSE 1 END As bit) As ReviewedByProvider,
                        CAST(CASE WHEN (SELECT count(*) FROM UserReviews As URC
                            WHERE URC.BookingID = B.BookingID
                                AND
                                URC.CustomerUserID = B.ClientUserID
                                AND 
                                URC.PositionID = B.JobTitleID
                        ) = 0 THEN 0 ELSE 1 END As bit) As ReviewedByCustomer
                FROM    Booking As B
                         INNER JOIN
                        CalendarEvents As E
                          ON B.ServiceDateID = E.Id
                WHERE   B.BookingStatusID IN (" +
                                   String.Join(",", new List <int> {
            (int)LcEnum.BookingStatus.confirmed, (int)LcEnum.BookingStatus.servicePerformed, (int)LcEnum.BookingStatus.completed
        }) + @")
                         AND
                        -- at 1 Week=168 hours, after service ended (between 168 and 175 hours -6 hours of margin-)
                        getdate() >= dateadd(hh, 168, E.EndTime)
                         AND
                        getdate() < dateadd(hh, 175, E.EndTime)
                         AND
                        B.MessagingLog not like '%[1W Review Reminder]%'
            "))
        {
            try
            {
                // We need check that there was not reviews already (why send a reminder for something
                // already done? just we avoid that!).
                // If both users did its reviews, nothing to send
                if (b.ReviewedByProvider && b.ReviewedByCustomer)
                {
                    // Next booking
                    continue;
                }
                char messageFor =
                    b.ReviewedByProvider ? 'c' :
                    b.ReviewedByCustomer ? 'p' :
                    'b';

                // Send message
                LcMessaging.SendBooking.For((int)b.BookingID).RequestToReviewReminder();

                // Update MessagingLog for the booking
                db.Execute(sqlAddBookingMessagingLog, b.BookingID, "[1W Review Reminder]");

                items++;
                if (messageFor == 'c' || messageFor == 'p')
                {
                    messages++;
                }
                else
                {
                    messages += 2;
                }
            }
            catch (Exception ex)
            {
                logger.LogEx("Booking Review Reminders 1W", ex);
            }
        }
        logger.Log("Total of Booking Review Reminders 1W: {0}, messages sent: {1}", items, messages);
        return(new TaskResult
        {
            ItemsReviewed = items,
            ItemsProcessed = items,
            MessagesSent = messages
        });
    }
Esempio n. 22
0
    /// <summary>
    /// Executes the page code of the desired method
    /// and returns an object with the result.
    /// That result must be piped to the response manually
    /// (or use JsonResponse).
    /// </summary>
    /// <param name="WebPage"></param>
    /// <returns></returns>
    public dynamic Run(System.Web.WebPages.WebPage WebPage)
    {
        this.WebPage = WebPage;

        dynamic result = null;

        // For all requests:
        // No cache
        WebPage.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
        WebPage.Response.Cache.SetValidUntilExpires(false);
        WebPage.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
        WebPage.Response.Cache.SetCacheability(HttpCacheability.NoCache);
        WebPage.Response.Cache.SetNoStore();
        // No cookies
        WebPage.Response.Cookies.Clear();

        try
        {
            switch (Request.HttpMethod.ToUpper())
            {
            case "GET":
                result = Get();
                break;

            case "POST":
                // By general, if everything goes fine, a 'post' must return
                // the http code '201:Created'. On any error will be replaced.
                // And can be explicitely replaced by the specific page on the
                // overrided 'Post()' method
                WebPage.Response.StatusCode = 201;
                result = Post();
                break;

            case "PUT":
                result = Put();
                break;

            case "DELETE":
                result = Delete();
                break;

            case "OPTIONS":
                // Just let asp.net to response empty with the
                // custom headers for CORS that were set in the web.config
                break;

            default:
                throw new HttpException(405, String.Format("{0} is not allowed", Request.HttpMethod));
            }
        }
        catch (ValidationException valEx)
        {
            result = new Dictionary <string, dynamic>();
            result["errorMessage"] = LcRessources.ValidationSummaryTitle;
            result["errorSource"]  = "validation";

            var errors = new System.Collections.Hashtable();
            if (!String.IsNullOrEmpty(valEx.ContainerName))
            {
                errors[valEx.ContainerName + "." + valEx.ParamName] = valEx.Message;
            }
            errors[valEx.ParamName] = valEx.Message;
            result["errors"]        = errors;

            WebPage.Response.StatusCode = 400;
        }
        catch (HttpException http)
        {
            result = new Dictionary <string, dynamic>();

            WebPage.Response.StatusCode = http.GetHttpCode();

            result["errorMessage"] = http.Message;
            if (!ModelState.IsValid)
            {
                result["errorSource"] = "validation";
                result["errors"]      = ModelState.Errors();
            }

            if (WebPage.Response.StatusCode == 500)
            {
                if (ASP.LcHelpers.InDev)
                {
                    result["exception"] = http;
                }
                else
                {
                    LcLogger.LogAspnetError(http);
                }
            }
        }
        catch (Exception ex)
        {
            result = new Dictionary <string, dynamic>();
            result["errorMessage"] = ex.Message;
            // Bad Format code for "Constraint" or Internal server error:
            WebPage.Response.StatusCode = ex is ConstraintException ? 400 : 500;

            if (ASP.LcHelpers.InDev)
            {
                result["exception"] = ex;
            }
            else
            {
                LcLogger.LogAspnetError(ex);
            }
        }

        return(result);
    }
Esempio n. 23
0
 private EarningsEntryReminderTask(LcLogger logger)
 {
     TaskStarted = DateTime.Now;
     this.logger = logger;
 }