Development of a mortgage calculator using 1C-Bitrix

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

Development of a Mortgage Calculator on 1C-Bitrix

A mortgage calculator is one of the most technically rich financial tools on a website. Unlike simple "area × price" multiplication, it involves annuity payment formulas, down payment accounting, insurance, and differentiated vs. annuity repayment types. At the same time, the user expects an instant answer — any delay is perceived as a site error.

The math: annuity payment

An annuity payment is the same amount every month. The formula:

P = S × r / (1 - (1 + r)^(-n))

Where:

  • P — monthly payment
  • S — loan amount (property price minus down payment)
  • r — monthly interest rate (annual ÷ 12 ÷ 100)
  • n — number of months

Implementation in PHP:

namespace MyProject\Services;

class MortgageCalculator
{
    public static function calculate(
        float $propertyPrice,
        float $downPayment,
        float $annualRate,
        int   $termYears
    ): array {
        $loanAmount  = $propertyPrice - $downPayment;
        $termMonths  = $termYears * 12;
        $monthlyRate = $annualRate / 12 / 100;

        if ($monthlyRate == 0) {
            // Zero-interest installment (rare but happens)
            $monthlyPayment = $loanAmount / $termMonths;
        } else {
            $monthlyPayment = $loanAmount
                * $monthlyRate
                * pow(1 + $monthlyRate, $termMonths)
                / (pow(1 + $monthlyRate, $termMonths) - 1);
        }

        $totalPayment   = $monthlyPayment * $termMonths;
        $totalInterest  = $totalPayment - $loanAmount;
        $overpaymentPct = ($totalInterest / $loanAmount) * 100;

        return [
            'loan_amount'        => round($loanAmount, 2),
            'monthly_payment'    => round($monthlyPayment, 2),
            'total_payment'      => round($totalPayment, 2),
            'total_interest'     => round($totalInterest, 2),
            'overpayment_pct'    => round($overpaymentPct, 1),
            'down_payment_pct'   => round(($downPayment / $propertyPrice) * 100, 1),
        ];
    }

    public static function buildPaymentSchedule(
        float $loanAmount,
        float $annualRate,
        int   $termMonths
    ): array {
        $schedule     = [];
        $monthlyRate  = $annualRate / 12 / 100;
        $monthlyPayment = $loanAmount
            * $monthlyRate
            * pow(1 + $monthlyRate, $termMonths)
            / (pow(1 + $monthlyRate, $termMonths) - 1);

        $balance = $loanAmount;

        for ($month = 1; $month <= $termMonths; $month++) {
            $interestPayment = $balance * $monthlyRate;
            $principalPayment = $monthlyPayment - $interestPayment;
            $balance -= $principalPayment;

            $schedule[] = [
                'month'     => $month,
                'payment'   => round($monthlyPayment, 2),
                'principal' => round($principalPayment, 2),
                'interest'  => round($interestPayment, 2),
                'balance'   => round(max($balance, 0), 2),
            ];
        }

        return $schedule;
    }
}

Payment schedule: table and chart

A full repayment schedule is a competitive advantage. The user can see how the principal debt decreases and how much goes toward interest in different periods. Chart.js or ApexCharts are used for visualization — lightweight libraries without unnecessary dependencies.

// Chart data comes from the server via AJAX
async function updateChart(params) {
    const response = await fetch('/ajax/mortgage/schedule/', {
        method: 'POST',
        body: new URLSearchParams({ ...params, sessid: BX.bitrix_sessid() }),
    });
    const data = await response.json();

    if (!data.success) return;

    // Group by year for the chart
    const years = [];
    const principalByYear = [];
    const interestByYear  = [];

    data.schedule.forEach((month, i) => {
        const yearIndex = Math.floor(i / 12);
        if (!years[yearIndex]) {
            years[yearIndex] = `Year ${yearIndex + 1}`;
            principalByYear[yearIndex] = 0;
            interestByYear[yearIndex]  = 0;
        }
        principalByYear[yearIndex] += month.principal;
        interestByYear[yearIndex]  += month.interest;
    });

    renderStackedBarChart(years, principalByYear, interestByYear);
}

Insurance accounting

Banks require insurance. The calculator must show the real cost:

  • Property insurance — 0.1–0.5% of property value per year
  • Life and health insurance — 0.3–1.5% of the loan balance (optional, but reduces the rate)
  • Title insurance — relevant for the secondary market
$annualInsurance = $loanAmount * ($insuranceRate / 100);
$monthlyInsurance = $annualInsurance / 12;
$totalMonthlyPayment = $monthlyPayment + $monthlyInsurance;

Bank comparison

For aggregators and developer websites — a comparison table of offers from several banks. Data is stored in an HL block and updated by a manager:

Bank Rate Down payment Term
Bank A 8.5% from 15% up to 30 years
Bank B 7.9% from 20% up to 25 years
Bank C 9.1% from 10% up to 30 years

Integration with the request form

The calculation result is passed to the request form as hidden fields — the manager can see what the client was considering:

document.getElementById('submit-btn').addEventListener('click', () => {
    document.getElementById('hidden-loan-amount').value  = currentResult.loan_amount;
    document.getElementById('hidden-monthly-pay').value  = currentResult.monthly_payment;
    document.getElementById('hidden-annual-rate').value  = currentParams.annualRate;
    document.getElementById('hidden-term-years').value   = currentParams.termYears;
});

Timelines

Task Timeline
Basic calculator (annuity, main fields, request form) 5–8 days
Calculator with payment schedule, chart, insurance accounting 2–3 weeks
Full mortgage aggregator with multiple banks, saved calculations 4–6 weeks

A mortgage calculator works when the math is correct and the UX is not intimidating. The client should get an answer within 2–3 seconds of interacting with the form — that is the criterion for a successful tool.