هر قبض یک شناسه قبض و یک شناسه پرداخت دارد که برای استعلام و پرداخت قبوض از آنها استفاده می‌شود. این دو عامل، اعدادی چند رقمی هستند که هر کدام از رقم‌های آن‌ها معنای خاصی دارد. در ادامه به توضیح این دو عدد و معنای رقم‌های آن و نحوه ایجاد آن می‌پردازیم.

شناسه قبض

شناسه قبض شامل حداقل ۶ و حداکثر ۱۳ رقم است. این عدد که مشخصات مشتری و نوع قبض (قبض گاز، قبض برق، قبض آب، قبض همراه اول و …) را مشخص می‌کند، همواره برای یک قبض خاص بدون تغییر است. برای مثال، شناسه قبض آب یک آدرس مشخص، در همه دوره‌ها و مستقل از میزان مصرف، یکسان است.

ارقام تشکیل دهنده شناسه قبض

  • کد پرونده، حداکثر ۸ رقم
  • کد شرکت تابعه، ۳ رقم
  • کد نوع خدمت، ۱ رقم
  • رقم کنترلی، ۱ رقم

کد پرونده: این کد معرف مشترکین شرکت‌های خدماتی است و هر مشترک یک کد پرونده منحصر به فرد دارد. پس از هر تراکنش پرداخت قبض بانک‌ها اطلاعات این کد را به همراه سایر ارقام شناسه برای شرکت‌های خدماتی (مانند شرکت آب و فاضلاب یا برق) ارسال می‌کنند. این شرکت‌ها به کمک کد پرونده تشخیص می‌دهند که کدام مشترک قبض خود را پرداخت کرده است.

کد شرکت تابعه: این کد که یک عدد سه رقمی است، شرکت تابعه صادر کننده قبض را مشخص می‌کند. برای مثال، شرکت توزیع نیروی برق اصفهان را می‌توان نام برد.

کد نوع خدمت: نوع قبض به کمک این کد یک رقمی قابل تشخیص است. در جدول زیر می‌توانید کد خدمات مختلف را مشاهده کنید:

کد۱۲۳۴۵۶۷۸9
نوع شرکتآببرقگازتلفن ثابتتلفن همراهعوارض شهرداریسازمان مالیاتجرایم رانندگیمتفرقه

رقم کنترلی شناسه: این رقم کنترل کننده‌ کلیه ارقام شناسه قبض است و از ورود اشتباه شناسه قبض جلوگیری می‌کند. رقم کنترلی با استفاده از فرمول زیر که فرمول باقی‌مانده مبنای ۱۱ است، محاسبه می‌شود. روش محاسبه رقم کنترلی به صورت زیر است:

  • از راست به چپ به هر رقم وزن داده می‌شود که از عدد ۲ شروع شده و تا ۷ ادامه پیدا می‌کند.
  • هر رقم در وزن خودش ضرب شده و حاصل جمع کل محاسبه می‌شود.
  • عدد نهایی بر ۱۱ تقسیم شده و اگر باقی‌مانده آن صفر یا یک شد رقم کنترلی صفر می‌شود.
  • برای سایر حالت‌ها باقی‌مانده از ۱۱ کم می‌شود و نتیجه تفریق برابر رقم کنترلی است.

شناسه پرداخت

شناسه پرداخت حداقل از ۶ رقم و حداکثر از ۱۳ رقم تشکیل شده است. مبلغ، سال و دوره قبض از این شناسه به ‌دست می‌آید.

ارقام تشکیل دهنده شناسه پرداخت

  • مبلغ: حداکثر ۸ رقم
  • کد سال: ۱ رقم
  • کد دوره: ۲ رقم
  • رقم کنترلی اول: ۱ رقم
  • رقم کنترلی دوم: ۱ رقم

مبلغ: با حذف سه صفر از سمت راست مبلغ، باقی‌مانده در این قسمت ثبت می‌شود. برای مثال اگر مبلغ قبضی ۱۳۲۰۰۰ ریال باشد، در این قسمت عدد ۱۳۲ ثبت می‌شود.

کد سال: شرکت‌های خدماتی به دو صورت این رقم را درج می‌کنند:

  1. رقم یکان سال صدور قبض: (مثلاً ۸ برای سال ۱۳۹۸)
  2. از رقم صفر برای سال اول، ۱ برای سال دوم و به همین ترتیب رقم ۹ برای دهمین سال صدور قبض، استفاده می‌شود. با شروع سال یازدم این عدد دوباره از صفر شروع می‌شود.

کد دوره: این کد، شماره دوره صدور هر قبض را مشخص می‌کند. برای مثال ۰۴ به معنای چهارمین دوره چاپ قبض در سال است.

رقم کنترلی اول: این رقم، کلیه ارقام شناسه پرداخت را که تا اینجا معرفی شدند، کنترل کرده و با توجه به فرمول مبنای ۱۱ که در قسمت شناسه قبض بررسی شد، محاسبه می‌شود.

رقم کنترلی دوم: برای محاسبه رقم کنترلی دوم، کلیه ارقام شناسه قبض و شناسه پرداخت را کنار هم قرار داده (ابتدا شناسه قبض در سمت چپ و سپس شناسه پرداخت، پس از حذف صفر از سمت چپ هر شناسه در صورت وجود) و بر روی تمام ارقام بر اساس فرمول مبنای ۱۱ محاسبه و اعمال می‌شود.

Center

کد CSharp تولید شناسه قبض و شناسه پرداخت به صورت زیر است:

 1using System.Globalization;
 2using System.Numerics;
 3
 4namespace BillNum
 5{
 6    /// <summary>
 7    /// تولید شناسه قبض و شناسه پرداخت
 8    /// </summary>
 9    public static class BillGenerator
10    {
11        private const int MinWeight = 2;
12        private const int MaxWeight = 7;
13
14        /// <summary>محاسبه شناسه قبض</summary>
15        /// <param name="directoryCode">شماره پرونده</param>
16        /// <param name="companyCode">کد شرکت</param>
17        /// <param name="billType">نوع قبض</param>
18        /// <returns></returns>
19        public static string GenerateBillId(string directoryCode, string companyCode, string billType)
20        {
21            ValidateNumeric(directoryCode, 1, 8, nameof(directoryCode), out _);
22            ValidateNumeric(companyCode, 3, 3, nameof(companyCode), out _);
23            ValidateNumeric(billType, 1, 1, nameof(billType), out _);
24
25            var billId = BigInteger.Parse($"{directoryCode}{companyCode}{billType}");
26            var digitCode = CalculateCheckDigit(billId);
27
28            return AppendCheckDigit(billId, digitCode);
29        }
30
31        /// <summary>محاسبه شناسه پرداخت</summary>
32        /// <param name="amount">مبلغ</param>
33        /// <param name="yearCode">کد سال</param>
34        /// <param name="termCode">کد دوره</param>
35        /// <param name="billId">شناسه قبض</param>
36        /// <returns></returns>
37        public static string GeneratePaymentId(string amount, string yearCode, string termCode, string billId)
38        {
39            ValidateNumeric(amount, 1, 11, nameof(amount), out var amountLong);
40            ValidateNumeric(yearCode, 1, 1, nameof(yearCode), out _);
41            ValidateNumeric(termCode, 2, 2, nameof(termCode), out _);
42            ValidateNumeric(billId, 13, 13, nameof(billId), out _);
43
44            var paymentId = BigInteger.Parse($"{amountLong / 1000}{yearCode}{termCode}");
45            var digitCode = CalculateCheckDigit(paymentId);
46            var paymentIdWithDigit = AppendCheckDigit(paymentId, digitCode);
47            var combined = BigInteger.Parse($"{billId}{paymentIdWithDigit}");
48            var finalDigit = CalculateCheckDigit(combined);
49
50            return AppendCheckDigit(BigInteger.Parse(paymentIdWithDigit), finalDigit);
51        }
52
53        private static string AppendCheckDigit(BigInteger inputCode, int digitCode)
54        {
55            var needsAdjustment = digitCode > 1;
56            var result = needsAdjustment
57                ? inputCode * 10 + (11 - digitCode)
58                : inputCode * 10;
59
60            return result.ToString(CultureInfo.InvariantCulture);
61        }
62
63        private static int CalculateCheckDigit(BigInteger inputCode)
64        {
65            var weight = MinWeight;
66            var sum = 0;
67            var temp = inputCode;
68
69            while (temp != 0)
70            {
71                sum += (int)(temp % 10 * weight);
72                temp /= 10;
73                weight = weight == MaxWeight ? MinWeight : weight + 1;
74            }
75
76            return sum % 11;
77        }
78
79        private static void ValidateNumeric(string value, int minLength, int maxLength, string paramName,
80            out ulong result)
81        {
82            if (!ulong.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out result)
83                || value.Length < minLength || value.Length > maxLength)
84                throw new ArgumentException($"The {paramName} is invalid.", paramName);
85        }
86    }
87}