示例#1
0
        /// <summary>
        ///     Processes all payroll for all organizations system-wide. Should run on the 1st of every month.
        /// </summary>
        public static void ProcessMonthly()
        {
            DateTime today = DateTime.UtcNow;

            string lastRun = Persistence.Key["LastSalaryRun"];

            string expectedLastRun = today.ToString("yyyyMM", CultureInfo.InvariantCulture);

            if (lastRun != null &&
                String.Compare(lastRun, expectedLastRun, CultureInfo.InvariantCulture, CompareOptions.IgnoreCase) >= 0)
            {
                // nothing to do, return

                return;
            }

            Persistence.Key["LastSalaryRun"] = expectedLastRun;

            // Process the payroll for all organizations. Assume payday is 25th.
            // TODO: Different payday per organization?

            Payroll  payroll = GetAll();
            DateTime payday  = new DateTime(today.Year, today.Month, 25);

            foreach (PayrollItem payrollItem in payroll)
            {
                Salary salary = Salary.Create(payrollItem, payday);
                SwarmopsLog.CreateEntry(payrollItem.Person, new SalaryCreatedLogEntry(salary));

                // TODO: CREATE SALARY SPECIFICATION, SEND TO PERSON
            }
        }
示例#2
0
        static public Salary Create(PayrollItem payrollItem, DateTime payoutDate)
        {
            // Load the existing adjustments.

            PayrollAdjustments adjustments = PayrollAdjustments.ForPayrollItem(payrollItem);

            Int64 payCents = payrollItem.BaseSalaryCents;

            // Apply all before-tax adjustments

            foreach (PayrollAdjustment adjustment in adjustments)
            {
                if (adjustment.Type == PayrollAdjustmentType.GrossAdjustment)
                {
                    payCents += adjustment.AmountCents;
                }
            }

            // calculate tax

            double subtractiveTax = TaxLevels.GetTax(payrollItem.Country, payrollItem.SubtractiveTaxLevelId, payCents / 100.0);

            if (subtractiveTax < 1.0)
            {
                // this is a percentage and not an absolute number

                subtractiveTax = payCents * subtractiveTax;
            }
            Int64 subtractiveTaxCents = (Int64)(subtractiveTax * 100);

            Int64 additiveTaxCents = (Int64)(payCents * payrollItem.AdditiveTaxLevel);

            payCents -= subtractiveTaxCents;

            // Apply all after-tax adjustments

            foreach (PayrollAdjustment adjustment in adjustments)
            {
                if (adjustment.Type == PayrollAdjustmentType.NetAdjustment)
                {
                    payCents += adjustment.AmountCents;
                }
            }

            // Create salary, close adjustments

            Salary salary = Salary.Create(payrollItem, payoutDate, payCents, subtractiveTaxCents, additiveTaxCents);

            // For each adjustment, close and bind to salary

            foreach (PayrollAdjustment adjustment in adjustments)
            {
                adjustment.Close(salary);
            }

            // If net is negative, create rollover adjustment

            if (payCents < 0)
            {
                PayrollAdjustment rollover1 = PayrollAdjustment.Create(payrollItem, PayrollAdjustmentType.NetAdjustment, -payCents,
                                                                       "Deficit rolls over to next salary");

                rollover1.Close(salary);

                PayrollAdjustment rollover2 = PayrollAdjustment.Create(payrollItem, PayrollAdjustmentType.NetAdjustment,
                                                                       -payCents, "Deficit rolled over from " +
                                                                       payoutDate.ToString("yyyy-MM-dd"));

                // keep rollover2 open, so the deficit from this salary is carried to the next

                salary.NetSalaryCents = 0;
            }

            // Add the financial transaction

            FinancialTransaction transaction =
                FinancialTransaction.Create(payrollItem.OrganizationId, DateTime.Now,
                                            "Salary #" + salary.Identity + ": " + payrollItem.PersonCanonical +
                                            " " +
                                            salary.PayoutDate.ToString("yyyy-MMM", CultureInfo.InvariantCulture));

            transaction.AddRow(payrollItem.Budget, salary.CostTotalCents, null);
            transaction.AddRow(payrollItem.Organization.FinancialAccounts.DebtsSalary, -salary.NetSalaryCents, null);
            transaction.AddRow(payrollItem.Organization.FinancialAccounts.DebtsTax, -salary.TaxTotalCents, null);
            transaction.Dependency = salary;

            // Finally, check if net and/or tax are zero, and if so, mark them as already-paid (i.e. not due for payment)

            if (salary.NetSalaryCents == 0)
            {
                salary.NetPaid = true;
            }

            if (salary.TaxTotalCents == 0)
            {
                salary.TaxPaid = true;
            }

            return(salary);
        }