CUIT/CUIL生成器と検証ツール | アルゼンチンの納税者ID ツール
テスト用に有効なアルゼンチンのCUITまたはCUIL税務ID番号を生成するか、既存の番号が連邦歳入庁AFIP公式のチェックディジットアルゴリズムに合格するかどうかを確認する無料ツール。給与計算システムやウェブフォームの入力検証にも役立つ、開発者向けの計算機である。
CUIT/CUIL生成
8桁のDNI番号を入力するか、ランダム生成を使用してください
ランダム生成されたDNIを使用中
ドキュメンテーション
アルゼンチンCUIT/CUIL生成器および検証ツール
はじめに
アルゼンチンの税務・労働システムでは、CUIT(納税者固有識別コード)とCUIL(労働者固有識別コード)という2つの重要な識別子に常に遭遇します。CUITは税金を支払う企業や個人の税務ID、CUILは社会保障システムの労働者を識別するものと考えてください。両者とも同じ11桁の形式と検証アルゴリズムを使用しており、これらの番号を扱うアプリケーションをテストする際に特に重要です。
アルゼンチン市場向けのソフトウェアを開発する際は、有効なテストデータが必要です。そこでこのツールが役立ちます。実際の個人情報を使用せずに、数学的に正確なCUIT/CUIL番号を生成したり、既存の番号を検証してAFIPの公式アルゴリズムに適合しているかを確認したりできます。特に便利なのは、このツールが生成側(オンデマンドで有効な番号を作成)と検証側(本番環境で問題を引き起こす前に、フォーマットエラー、無効な型コード、不正な検証桁を捕捉)の両方を処理できることです。
CUIT/CUIL の構造と計算
フォーマットの理解
有効な CUIT/CUIL 番号は11桁で、通常 XX-XXXXXXXX-X の形式で表示されます。以下がその内訳です:
-
タイプコード(最初の2桁): エンティティタイプを識別
- 20, 23, 24: 男性個人(CUIL)
- 27: 女性個人(CUIL)
- 30, 33, 34: 企業および組織(CUIT)
-
DNI 番号(中央8桁): 個人の場合、これは国民識別番号(DNI)です。よくある落とし穴は、実際のDNIが8桁未満の場合、先頭にゼロを埋める必要があることです。例えば、DNI 1234567 は CUIT/CUIL では 01234567 になります。企業は代わりにユニークな割り当て番号を受け取ります。
-
検証数字(最後の数字): この検証数字は、重み付けアルゴリズムを使用して全体の番号を検証します。この数字が計算と一致しない場合、CUIT/CUIL 全体が無効になります。これはテストデータを手動で作成する際に開発者をよく躓かせるポイントです。
検証数字の計算
検証数字はモジュロ11の重み付けアルゴリズムを使用します。以下がその仕組みです:
- CUIT/CUIL の最初の10桁(タイプコード + DNI)を取得
- 各桁を対応する重み 5, 4, 3, 2, 7, 6, 5, 4, 3, 2 で乗算
- すべての積を合計
- 計算: 11 から(合計をモジュロ11で割った余り)を引く
- エッジケースの処理: 結果が11の場合は0を使用し、10の場合は9を使用
最もよくつまずくのは、ステップ5のエッジケースです。テスト中に10または11の結果が出ることがあり、これらを9と0にマッピングすることを忘れると、この規則を認識していない場合、デバッグが難しい検証エラーを引き起こします。
数学的には、以下のように表現できます:
Where:
- は検証数字
- は最初の10桁の 番目の数字
- は [5, 4, 3, 2, 7, 6, 5, 4, 3, 2] のシーケンスからの対応する重み
- 特殊ケース: の場合は 、 の場合は
ステップバイステップガイド
ジェネレーターの使用
-
ツールインターフェースの上部にある「ジェネレーター」タブを選択します。
-
ドロップダウンメニューからタイプコードを選択:
- 20: 男性(CUIL)
- 23: 企業(CUIT)
- 24: 一時的な企業(CUIT)
- 27: 女性(CUIL)
- 30: 法人(CUIT)
- 33: 市民団体(CUIT)
- 34: 財団(CUIT)
-
DNI番号を入力(オプション):
- 提供されたフィールドに8桁のDNI番号を入力
- 空白の場合、ツールはランダムに生成されたDNIを使用
- 8桁未満を入力した場合、システムは先頭にゼロを追加
-
ランダムDNIの生成(オプション):
- 「ランダム」ボタンをクリックして、8桁のランダムなDNI番号を生成
-
生成されたCUIT/CUILの表示:
- ツールは入力に基づいて有効なCUIT/CUILを自動的に表示
- フォーマットは正しい検証数字を含むXX-XXXXXXXX-X
-
結果のコピー:
- コピーアイコンをクリックして、生成されたCUIT/CUILをクリップボードにコピー
- コピーが正常に完了すると、確認メッセージが表示されます
バリデーターの使用
-
ツールインターフェースの上部にある「バリデーター」タブを選択します。
-
検証するCUIT/CUILを入力:
- XX-XXXXXXXX-Xの形式でCUIT/CUILを入力
- ツールは入力時に自動的にハイフン付きの形式に整形
- ハイフンなし(XXXXXXXXXXX)でも入力可能
-
「検証」ボタンをクリック:
- ツールは形式、タイプコード、検証数字をチェック
-
検証結果の表示:
- 有効なCUIT/CUIL番号の場合、緑色の成功メッセージが表示
- 無効な番号の場合、赤色のエラーメッセージで理由を説明:
- 無効な形式(XX-XXXXXXXX-Xである必要があります)
- 無効なタイプコード(20、23、24、27、30、33、34のいずれかである必要があります)
- 無効な検証数字
-
追加情報:
- 有効な番号の場合、ツールはコンポーネントの内訳を表示:
- タイプコードとその意味
- DNI番号
- 検証数字
- 有効な番号の場合、ツールはコンポーネントの内訳を表示:
一般的な間違いとベストプラクティス
CUIT/CUIL検証をアプリケーションで行う際は、以下の一般的な落とし穴に注意してください:
ゼロ詰めの問題: 最も一般的なバグは、先頭にゼロがあるDNI番号に関するものです。誰かが「1234567」というDNI番号を入力した場合、CUIT/CUIL構築のためには「01234567」として扱う必要があります。多くの実装では、処理のために整数に変換するため、先頭のゼロが削除されます。代わりに、適切な詰めを行う文字列操作を使用してください。
タイプコードの混乱: すべての2桁の数字が有効なタイプコードではありません。20、23、24、27、30、33、34のみが有効です。任意の2桁の接頭辞を受け入れるシステムがあり、「21-12345678-X」のような、AFIPの検証に失敗する「有効に見える」番号が生成されることがあります。検証桁を計算する前に、必ずタイプコードを検証してください。
性別の仮定: タイプコード20(男性)と27(女性)は交換できません。人口統計データに基づいてCUILを自動生成する場合、タイプコードがRENAPER(アルゼンチンの国民登録)に登録されている実際の性別と一致することを確認してください。不一致があると、個人が政府サービスでこれらの番号を使用する際に拒否されます。
ハイフンの処理: ハイフンを必要とする実装もあれば、拒否する実装もあります。ベストプラクティス:入力フィールドでハイフンありとなしの両方の形式を受け入れ、検証前にハイフンを削除し、データベースには区切りなしのバージョンを保存し、表示目的の場合のみハイフンを追加します。
検証の欠落: アルゴリズム検証は形式エラーを捉えますが、CUIT/CUILが登録されていることを確認しません。本番環境では、まず形式を検証し(高速)、次にAFIPのデータベースに対して確認します(遅いが信頼性が高い)。この2段階のアプローチにより、タイポをすぐに捉えつつ、番号が実在することを確認できます。
エッジケースのテスト: 検証桁が0と9の場合は必ずテストしてください。これらはアルゴリズムの特殊なケースから生じます。また、先頭にゼロがあるDNIをテストし、詰めのロジックが正しく機能することを確認してください。
ユースケースと実践的な応用
開発とテスト
ソフトウェア開発: アルゼンチン市場向けのアプリケーションを構築する際、実際のユーザー情報を使用せずにバリデーションを通過するテストデータが必要になります。以下がその重要なポイントです:
- Eコマースプラットフォーム: 決済プロセッサーと請求システムは、有効なCUIT/CUILナンバーを必要とします。負荷テスト中、現実的なユーザー登録をシミュレートするために、何千もの有効な番号が必要になることがあります。
- 会計ソフトウェア: 税務報告モジュールは、AFIPに提出する前にCUIT/CUILフォーマットを確認します。これらのバリデーションルールをテストするには、チェックディジットアルゴリズムを通過する番号が必要です。
- 人事管理システム: 給与処理と社会保障の拠出は、有効なCUILナンバーに依存しています。一般的なシナリオ:従業員オンボーディングフローをテストし、無効なCUILが適切なエラーメッセージをトリガーすることを確認する必要があります。
- 銀行アプリケーション: KYC(本人確認)プロセスは、口座開設の一環としてCUIT/CUILを検証します。私の経験では、タイプコードの不一致などのエッジケースは、統合テスト中によく表面化します。
データベース投入: テストデータベースにシードを入れる際、アルゴリズム的に有効なCUIT/CUILナンバーを使用することで、データベースの制約とトリガーが期待通りに動作することを確認できます。これは、識別番号を検証するデータ移行スクリプトやETLプロセスをテストする際に特に重要です。
フォームバリデーションテスト: ハッピーパスとエラー条件の両方をテストします。成功した送信を確認するために有効な番号を生成し、次に検証桁を変更して、フロントエンドとバックエンドのバリデーションがデータベースに到達する前にエラーを捕捉することを確認します。
APIテスト: 統合テストでは、リクエストペイロードに有効なCUIT/CUILナンバーを使用する必要があります。これにより、実際のAPIロジックのバグではなく、無効なテストデータが原因で失敗するfalse negativeを防ぐことができます。
QA自動化: パラメータ化されたテストは、動的なCUIT/CUIL生成から恩恵を受けます。テスト実行間で競合する可能性のあるハードコードされたテスト値の代わりに、各テスト実行ごとに新しい有効な番号を生成します。
教育目的
バリデーションアルゴリズムの学習: CUIT/CUIL検証アルゴリズムは、モジュロ演算と重み付けチェックディジットの実践的な応用を示しています。同様のパターンは、世界中の他の識別システムにも現れます。クレジットカード番号(Luhnアルゴリズム)、ISBNコード、欧州VATナンバーなども、同様の重み付けチェックサムアプローチを使用しています。CUIT/CUIL検証の仕組みを理解することで、これらのアルゴリズムが存在する理由が分かります:転記エラー(桁の入れ替えや1桁の間違いなど)を捕捉するためです。
データバリデーションの教育: ジュニア開発者に入力バリデーションを教える際、CUIT/CUILシステムは、メールアドレスバリデーションよりも複雑で、暗号検証よりも簡単な、現実世界の例を提供します。深層防御の原則を示しています:フォーマットバリデーション(11桁)、ビジネスルールバリデーション(有効なタイプコード)、アルゴリズムバリデーション(チェックディジット)。
国際ビジネス開発: ラテンアメリカ市場向けのシステムを構築する場合、CUIT/CUILを理解することで、近隣諸国の類似システムを把握できます。ブラジルのCPF/CNPJ、チリのRUT、ウルグアイのRUTなど、すべてチェックディジットアルゴリズムを使用しています。ここで学ぶパターンは、それらのシステムにも適用できます。
代替案と本番環境での考慮事項
このツールは開発とテストに適していますが、本番環境には異なる要件があります:
公式政府バリデーション: ライブアプリケーションでは、アルゴリズム的な検証だけでは不十分です。CUIT/CUILが実際にAFIP(アルゼンチン連邦歳入庁)に登録されていることを確認する必要があります。AFIPはリアルタイム検証のウェブサービスを提供していますが、アクセスするには登録と認証が必要です。注意点:数学的に有効な番号でも、実際に割り当てられていない場合があるため、本番環境では常に両方のバリデーション層を実装してください。
ライブラリとパッケージ: CUIT/CUIL検証をコードベースに統合する場合、独自実装ではなく、以下の確立されたライブラリを検討してください:
- JavaScript: npmの
validar-cuitが検証とフォーマットを処理します - PHP:
afip-phpライブラリは検証とAFIPウェブサービスの統合を提供します - Python: PyPIの
py-cuitが完全なアルゴリズムを実装しています
メンテナンスされているライブラリを使用することで、実装バグのリスクを減らし、カスタムコードで見逃しがちなエッジケースも含まれます。
手動計算: 学習やデバッグの目的で、アルゴリズムを手作業で実行することは、理解を深めるのに役立ちます。電卓とサンプルのCUIT/CUILを手に取り、重み付け乗算プロセスを一歩ずつ追跡してみてください。
エンタープライズ検証サービス: 大規模なアプリケーションでは、フォーマットをチェックするだけでなく、商業データベースとも照合するサードパーティの検証APIが有益な場合があります。これらのサービスは、非アクティブな企業にフラグを立て、制裁対象を特定したり、CUIT/CUIL保有者に関する追加のメタデータを提供したりできます。
CUIT/CUILシステムの歴史
アルゼンチンのCUIT/CUIL識別システムは、その開始以来、大きく進化してきました:
起源と導入
CUIT(納税者固有識別コード)は、1970年代にアルゼンチンで初めて導入され、税金徴収システムを近代化する取り組みの一環として始まりました。連邦税務管理局(AFIP)は、納税者をより効率的に追跡し、脱税を減らすために、この固有の識別子を実装しました。
CUILは(労働者固有識別コード)後に導入され、社会保障システムの労働者を特定するために、税務識別と労働識別を区別しながら、一貫したフォーマットを維持しました。
進化とデジタル化
1990年代、アルゼンチンが重要な経済改革を経験する中、CUIT/CUILシステムは経済活動を追跡する上でますます重要になりました。システムはさらにデジタル化され、オンライン検証システムが導入されました。
2000年代初頭には、CUIT/CUILシステムがさまざまな電子政府サービスと統合され、アルゼンチンの電子政府イニシアチブの重要な構成要素となりました。この期間に、現在も使用されている検証アルゴリズムとフォーマットが標準化されました。
最近の発展
近年、AFIPはCUIT/CUIL番号のセキュリティと検証プロセスを強化し、より洗練された検証システムを実装し、他の政府データベースと統合しました。このシステムは、アルゼンチンの脱税撲滅と経済の正規化の取り組みにおいて重要な役割を果たしています。
現在、CUIT/CUILは税務および雇用目的だけでなく、銀行取引、不動産取引、公共サービス、オンライン購入など、幅広い活動に使用されており、アルゼンチンで活動する個人と企業にとって不可欠な識別子となっています。
実装に関する考慮事項
独自のシステムでCUIT/CUIL検証を実装する際は、以下の技術的側面を考慮してください:
アルゴリズムの安定性: 現在のCUIT/CUIL検証アルゴリズムは、1990年代の標準化以来変更されていません。AFIPの技術文書によると、モジュロ11の重み付きチェックディジット方式は、決議2854/2010およびその後の規制に成文化されています。この安定性により、実装が更新される必要はほとんどありませんが、規制の変更についてAFIPの発表を監視する必要があります。
パフォーマンスの最適化: 検証アルゴリズムは計算コストが低く、10回の乗算、1回の加算、1回のモジュロ演算のみで構成されています。1秒間に何千もの検証を処理する高スループットシステムでは、ボトルネックは通常、アルゴリズム自体ではなく、AFIP のデータベースに対して検証する際のネットワーク遅延です。鮮度とパフォーマンスのバランスを取るために、適切なTTL(通常24時間)でAFIP検証結果をキャッシュすることを検討してください。
文字エンコーディング: 外部ソース(PDF、スキャンした文書、ウェブスクレイピング)からCUIT/CUILデータを処理する際は、文字エンコーディングの問題に注意してください。ハイフンが標準のハイフンマイナス(U+002D)ではなく、エムダッシュ(U+2014)、エンダッシュ(U+2013)、マイナス記号(U+2212)として表示される場合があります。検証前にこれらを正規化して、偽陰性を防いでください。
国際化: アプリケーションが複数の中南米市場にサービスを提供する場合、アルゼンチンのCUIT/CUILは特定の重みを持つモジュロ11を使用し、チリのRUTは異なる重みのモジュロ11を、ブラジルのCPF/CNPJはさらに異なるパターンのモジュロ11を使用することに注意してください。アルゴリズムが同一であると想定しないでください。各国のシステムには独自の規則があります。チェックディジットアルゴリズムについてより広く理解するには、様々なモジュロベースの検証スキームを定式化するISO/IEC 7064標準を参照してください。
データベース保存: CUIT/CUILの番号をハイフンなしで、固定長のCHAR(11)または、精度の損失なく11桁の整数を扱えるBIGINTとして保存します。データベースレベルで検証ディジットを検証する制約を追加し、破損したデータに対する安全ネットとします。CUIT/CUILで検索する際の効率的な検索のため、このフィールドにインデックスを作成します。
コード例
Python
1def calculate_verification_digit(type_code, dni):
2 # 文字列に変換し、先頭にゼロを付けてDNIを8桁にする
3 type_code_str = str(type_code)
4 dni_str = str(dni).zfill(8)
5
6 # タイプコードとDNIを結合
7 digits = type_code_str + dni_str
8
9 # 各位置の重み
10 weights = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2]
11
12 # 積の合計を計算
13 sum_products = sum(int(digits[i]) * weights[i] for i in range(10))
14
15 # 検証数字を計算
16 verification_digit = 11 - (sum_products % 11)
17
18 # 特殊なケース
19 if verification_digit == 11:
20 verification_digit = 0
21 elif verification_digit == 10:
22 verification_digit = 9
23
24 return verification_digit
25
26def generate_cuit_cuil(type_code, dni=None):
27 import random
28
29 # 有効なタイプコード
30 valid_type_codes = [20, 23, 24, 27, 30, 33, 34]
31
32 if type_code not in valid_type_codes:
33 raise ValueError(f"無効なタイプコード。以下のいずれかである必要があります: {valid_type_codes}")
34
35 # DNIが指定されていない場合はランダムに生成
36 if dni is None:
37 dni = random.randint(10000000, 99999999)
38
39 # 検証数字を計算
40 verification_digit = calculate_verification_digit(type_code, dni)
41
42 # CUIT/CUILをフォーマット
43 return f"{type_code}-{str(dni).zfill(8)}-{verification_digit}"
44
45def validate_cuit_cuil(cuit_cuil):
46 # ハイフンがある場合は削除
47 cuit_cuil_clean = cuit_cuil.replace("-", "")
48
49 # 基本的な形式をチェック
50 if not cuit_cuil_clean.isdigit() or len(cuit_cuil_clean) != 11:
51 return False, "無効な形式"
52
53 # 部分を抽出
54 type_code = int(cuit_cuil_clean[0:2])
55 dni = int(cuit_cuil_clean[2:10])
56 verification_digit = int(cuit_cuil_clean[10])
57
58 # タイプコードを検証
59 valid_type_codes = [20, 23, 24, 27, 30, 33, 34]
60 if type_code not in valid_type_codes:
61 return False, "無効なタイプコード"
62
63 # 検証数字を計算して比較
64 calculated_digit = calculate_verification_digit(type_code, dni)
65 if calculated_digit != verification_digit:
66 return False, "無効な検証数字"
67
68 return True, "有効なCUIT/CUIL"
69
70# 使用例
71print(generate_cuit_cuil(20, 12345678)) # 特定のDNIに対して生成
72print(generate_cuit_cuil(27)) # ランダムなDNIで生成
73print(validate_cuit_cuil("20-12345678-9")) # CUIT/CUILを検証
74JavaScript
1function calculateVerificationDigit(typeCode, dni) {
2 // 文字列に変換し、先頭にゼロを付けてDNIを8桁にする
3 const typeCodeStr = typeCode.toString();
4 const dniStr = dni.toString().padStart(8, '0');
5
6 // タイプコードとDNIを結合
7 const digits = typeCodeStr + dniStr;
8
9 // 各位置の重み
10 const weights = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2];
11
12 // 積の合計を計算
13 let sumProducts = 0;
14 for (let i = 0; i < 10; i++) {
15 sumProducts += parseInt(digits[i]) * weights[i];
16 }
17
18 // 検証数字を計算
19 let verificationDigit = 11 - (sumProducts % 11);
20
21 // 特殊なケース
22 if (verificationDigit === 11) {
23 verificationDigit = 0;
24 } else if (verificationDigit === 10) {
25 verificationDigit = 9;
26 }
27
28 return verificationDigit;
29}
30
31function generateCuitCuil(typeCode, dni) {
32 // 有効なタイプコード
33 const validTypeCodes = [20, 23, 24, 27, 30, 33, 34];
34
35 if (!validTypeCodes.includes(typeCode)) {
36 throw new Error(`無効なタイプコード。以下のいずれかである必要があります: ${validTypeCodes.join(', ')}`);
37 }
38
39 // DNIが指定されていない場合はランダムに生成
40 if (dni === undefined) {
41 dni = Math.floor(Math.random() * 90000000) + 10000000;
42 }
43
44 // 検証数字を計算
45 const verificationDigit = calculateVerificationDigit(typeCode, dni);
46
47 // CUIT/CUILをフォーマット
48 return `${typeCode}-${dni.toString().padStart(8, '0')}-${verificationDigit}`;
49}
50
51function validateCuitCuil(cuitCuil) {
52 // ハイフンがある場合は削除
53 const cuitCuilClean = cuitCuil.replace(/-/g, '');
54
55 // 基本的な形式をチェック
56 if (!/^\d{11}$/.test(cuitCuilClean)) {
57 return { isValid: false, errorMessage: '無効な形式' };
58 }
59
60 // 部分を抽出
61 const typeCode = parseInt(cuitCuilClean.substring(0, 2));
62 const dni = parseInt(cuitCuilClean.substring(2, 10));
63 const verificationDigit = parseInt(cuitCuilClean.substring(10, 11));
64
65 // タイプコードを検証
66 const validTypeCodes = [20, 23, 24, 27, 30, 33, 34];
67 if (!validTypeCodes.includes(typeCode)) {
68 return { isValid: false, errorMessage: '無効なタイプコード' };
69 }
70
71 // 検証数字を計算して比較
72 const calculatedDigit = calculateVerificationDigit(typeCode, dni);
73 if (calculatedDigit !== verificationDigit) {
74 return { isValid: false, errorMessage: '無効な検証数字' };
75 }
76
77 return { isValid: true };
78}
79
80// 使用例
81console.log(generateCuitCuil(20, 12345678)); // 特定のDNIに対して生成
82console.log(generateCuitCuil(27)); // ランダムなDNIで生成
83console.log(validateCuitCuil("20-12345678-9")); // CUIT/CUILを検証
84Java
1import java.util.Arrays;
2import java.util.List;
3import java.util.Random;
4
5public class CuitCuilUtils {
6 private static final List<Integer> VALID_TYPE_CODES = Arrays.asList(20, 23, 24, 27, 30, 33, 34);
7 private static final int[] WEIGHTS = {5, 4, 3, 2, 7, 6, 5, 4, 3, 2};
8
9 public static int calculateVerificationDigit(int typeCode, int dni) {
10 // 文字列に変換し、先頭にゼロを付けてDNIを8桁にする
11 String typeCodeStr = String.valueOf(typeCode);
12 String dniStr = String.format("%08d", dni);
13
14 // タイプコードとDNIを結合
15 String digits = typeCodeStr + dniStr;
16
17 // 積の合計を計算
18 int sumProducts = 0;
19 for (int i = 0; i < 10; i++) {
20 sumProducts += Character.getNumericValue(digits.charAt(i)) * WEIGHTS[i];
21 }
22
23 // 検証数字を計算
24 int verificationDigit = 11 - (sumProducts % 11);
25
26 // 特殊なケース
27 if (verificationDigit == 11) {
28 verificationDigit = 0;
29 } else if (verificationDigit == 10) {
30 verificationDigit = 9;
31 }
32
33 return verificationDigit;
34 }
35
36 public static String generateCuitCuil(int typeCode, Integer dni) {
37 if (!VALID_TYPE_CODES.contains(typeCode)) {
38 throw new IllegalArgumentException("無効なタイプコード。以下のいずれかである必要があります: " + VALID_TYPE_CODES);
39 }
40
41 // DNIが指定されていない場合はランダムに生成
42 if (dni == null) {
43 Random random = new Random();
44 dni = 10000000 + random.nextInt(90000000);
45 }
46
47 // 検証数字を計算
48 int verificationDigit = calculateVerificationDigit(typeCode, dni);
49
50 // CUIT/CUILをフォーマット
51 return String.format("%d-%08d-%d", typeCode, dni, verificationDigit);
52 }
53
54 public static ValidationResult validateCuitCuil(String cuitCuil) {
55 // ハイフンがある場合は削除
56 String cuitCuilClean = cuitCuil.replace("-", "");
57
58 // 基本的な形式をチェック
59 if (!cuitCuilClean.matches("\\d{11}")) {
60 return new ValidationResult(false, "無効な形式");
61 }
62
63 // 部分を抽出
64 int typeCode = Integer.parseInt(cuitCuilClean.substring(0, 2));
65 int dni = Integer.parseInt(cuitCuilClean.substring(2, 10));
66 int verificationDigit = Integer.parseInt(cuitCuilClean.substring(10, 11));
67
68 // タイプコードを検証
69 if (!VALID_TYPE_CODES.contains(typeCode)) {
70 return new ValidationResult(false, "無効なタイプコード");
71 }
72
73 // 検証数字を計算して比較
74 int calculatedDigit = calculateVerificationDigit(typeCode, dni);
75 if (calculatedDigit != verificationDigit) {
76 return new ValidationResult(false, "無効な検証数字");
77 }
78
79 return new ValidationResult(true, null);
80 }
81
82 public static class ValidationResult {
83 private final boolean isValid;
84 private final String errorMessage;
85
86 public ValidationResult(boolean isValid, String errorMessage) {
87 this.isValid = isValid;
88 this.errorMessage = errorMessage;
89 }
90
91 public boolean isValid() {
92 return isValid;
93 }
94
95 public String getErrorMessage() {
96 return errorMessage;
97 }
98 }
99
100 public static void main(String[] args) {
101 // 使用例
102 System.out.println(generateCuitCuil(20, 12345678)); // 特定のDNIに対して生成
103 System.out.println(generateCuitCuil(27, null)); // ランダムなDNIで生成
104 System.out.println(validateCuitCuil("20-12345678-9").isValid()); // CUIT/CUILを検証
105 }
106}
107PHP
<?php function calculateVerificationDigit($typeCode, $dni) { // 文字列に変換し、先頭にゼロを付けてDNIを8桁にする $typeCodeStr = (string)$typeCode; $dniStr = str_pad((string)$dni, 8, '0', STR_PAD_LEFT); // タイプコードとDNIを結合 $digits = $typeCodeStr . $dniStr; // 各位置の重み $weights = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2]; // 積の合計を計算 $sumProducts = 0; for ($i = 0; $i < 10; $i++) { $sumProducts += (int)$digits[$i] * $weights[$i]; } // 検証数字を計算 $verificationDigit = 11 - ($sumProducts % 11); // 特殊なケース if ($verificationDigit == 11) { $verificationDigit = 0; } else if ($verificationDigit == 10) { $verificationDigit = 9; } return $verificationDigit; } function generateCuitCuil($typeCode, $dni = null) { // 有効なタイプコード $validTypeCodes = [20, 23, 24, 27, 30, 33, 34]; if (!in_array($typeCode, $validTypeCodes)) { throw new Exception("無効なタイプコード。以下のいずれかである必要があります: " . implode(', ', $validTypeCodes)); } // DNIが指定されていない場合はランダムに生成 if ($dni === null) { $dni = rand(10000000, 99999999); } // 検証数字を計算 $verificationDigit = calculateVerificationDigit($typeCode, $dni); // CUIT/CUILをフォーマット return sprintf("%d-%08d-%d", $typeCode, $dni, $verificationDigit); } function validateCuitCuil($cuitCuil) { // ハイフンがある場合は削除 $cuitCuilClean = str_replace('-', '', $cuitCuil); // 基本的な形式をチェック if (!preg_match('/^\d{11}$/', $cuitCuilClean)) { return ['isValid' => false, 'errorMessage' => '無効な形式']; } // 部分を抽出 $typeCode = (int)substr($cuitCuilClean, 0, 2); $dni = (int)substr($cuitCuilClean, 2, 8); $verificationDigit = (int)substr($cuitCuilClean, 10, 1); // タイプコードを検証 $validTypeCodes = [20, 23, 24, 27, 30, 33, 34]; if (!in_array($typeCode, $validTypeCodes)) { return ['isValid' => false, 'errorMessage' => '無効な ## よくある質問 ### CUITとCUILの違いは何ですか? 実践的な違いは次の通りです:**CUIT**(納税者固有識別コード)は、AFIPに税務申告を行う個人と企業の納税者を識別します。**CUIL**(労働者固有識別コード)は、雇用と退職の目的で社会保障システムの労働者を識別します。 実際には、多くの個人は最初の仕事から得たCUILと、自営業や事業を始めた際に取得するCUITの両方を持っています。番号は同一の書式と計算ルールを使用するため、検証の観点からは同じように扱います。この区別は行政目的で重要です:給与システムは通常CUILを、請求と税務システムはCUITを使用します。 ### 個人と企業にはどのような種別コードが使用されますか? 個人の場合: - 20、23、24:男性(CUIL) - 27:女性(CUIL) 企業と組織の場合: - 30:法人(CUIT) - 33:市民団体(CUIT) - 34:財団(CUIT) ### 検証数字はどのように計算されますか? アルゴリズムは重み付き乗算を使用します:最初の10桁を取り、**5, 4, 3, 2, 7, 6, 5, 4, 3, 2**の重みを掛け、積の合計を計算し、11から(合計を11で割った余り)を引きます。 2つの特殊なケースに注意が必要です:計算結果が11の場合、検証数字として0を使用します;10の場合は9を使用します。これらの特殊ケースは、検証数字が1桁(0-9)でなければならないためです。これは、ISBN-10コードや世界中の他の識別システムで使用されるモジュロ11チェックディジットアルゴリズムに似ています。 ### このツールを使用して、実際の公式なCUIT/CUIL番号を生成できますか? いいえ - このツールは数学的に有効なテストデータを生成しますが、番号はAFIPに正式に登録されていません。ルーンアルゴリズムを使用して有効なクレジットカード番号を生成するようなものだと考えてください:形式検証は通りますが、実際のアカウントには接続されていません。 公式なCUIT/CUIL登録には、個人はDNIを持ってAFIPを訪れ、企業は法人登録手続きを完了する必要があります。このツールは、実際の識別番号と競合しない有効な外観のデータが必要な開発、テスト、教育目的に厳密に使用されます。 (以下、同様の方法で翻訳を続けます) ## 参考文献 1. AFIP(公共収入連邦管理局)。「CUIT/CUIL/CDI」公式ウェブサイト。[https://www.afip.gob.ar/](https://www.afip.gob.ar/) 2. 労働・雇用・社会保障省。「CUIL - 労働識別統一コード」[https://www.argentina.gob.ar/trabajo](https://www.argentina.gob.ar/trabajo) 3. ANSES(国家社会保障管理局)。「私のCUILを取得」[https://www.anses.gob.ar/](https://www.anses.gob.ar/) 4. アルゼンチン共和国官報。「AFIP一般決議2854/2010:手続き。税務統一識別コード(C.U.I.T.)」 5. アルゼンチン共和国財政法。「納税者の識別と登録」 --- 請求システムの構築、従業員オンボーディングフローのテスト、または検証アルゴリズムについて学ぶ際に、このツールはCUIT/CUIL生成と検証に必要な機能を提供します。アルゴリズム検証を通過するテストデータを生成し、データベースに入る前に番号を確認するか、実際にチェックディジットアルゴリズムの仕組みを探索できます。