#!/usr/bin/env python3
"""Perbaikan harian tslaw.id 2026-10-10 - post 3234
/cara-daftar-cv-pt-online/

Dasar pemilihan (audit drafts/tslaw_audit_selaras.json, snapshot 8 Okt 2026):
- Prioritas 1 sudah habis: 7 artikel yang punya tayangan GSC > 0 / posisi 11-30
  (3065, 3057, 3233, 3208, 3230, 2940, 2823) semuanya sudah digarap 2-8 Okt 2026.
  Data GSC baru tidak bisa ditarik: token OAuth atun masih dicabut (invalid_grant).
- Prioritas 2 = artikel 600-900 kata. Di antara yang belum digarap, #3234 adalah
  yang permintaannya paling kuat: 10 sesi GA4 90 hari (tertinggi di kelompok ini,
  setelah #3232 yang dikerjakan 9 Okt). Panjang sekarang 658 kata (tanpa skema).

Perbaikan HARI INI = panjangkan artikel menjadi 1.000+ kata dengan isi baru yang
berguna (kewajiban rutin setelah badan usaha berdiri, penyebab pendaftaran ditolak,
pilihan badan hukum untuk tender/kredit, dan bagian yang sebaiknya tidak dikerjakan
sendiri). Judul, slug, meta description, tombol WhatsApp, dan skema FAQPage tidak
diubah karena sudah benar. Tautan pilar /law-firm-surabaya/ sengaja TIDAK
ditambahkan: itu perbaikan prioritas 5 untuk hari lain (tepat 1 perbaikan per hari).

Fakta di isi baru sudah diverifikasi lewat pencarian (tslaw_cek_fakta_20261010.py):
- LKPM: menengah & besar triwulanan, kecil semesteran, mikro dikecualikan.
- PT Perorangan (Pasal 153A UU Cipta Kerja): usaha mikro & kecil, 1 pendiri,
  tanpa akta notaris, lewat surat pernyataan.
- Sekutu aktif CV bertanggung jawab sampai harta pribadi (Pasal 21 KUHD).

Jalankan tanpa argumen = dry run. Tambah --apply untuk menulis via REST (JSON).
"""
import base64, html as htmlmod, json, os, re, sys
import urllib.request, urllib.error

WS = "/home/mantapman/.hermes/profiles/atun/workspace"
sys.path.insert(0, WS)
from cfg_tslaw import CFG

AUTH = base64.b64encode(f"{CFG['user']}:{CFG['pass']}".encode()).decode()
BASE = "https://tslaw.id/wp-json/wp/v2"
HDR = {"Authorization": f"Basic {AUTH}", "User-Agent": "Mozilla/5.0"}

PID = 3234
OUT = f"{WS}/tslaw_pemulihan/perbaikan_20261010"
os.makedirs(OUT, exist_ok=True)
APPLY = "--apply" in sys.argv


def rest_get(path, timeout=120):
    req = urllib.request.Request(BASE + path, headers=HDR)
    with urllib.request.urlopen(req, timeout=timeout) as r:
        return json.load(r)


def rest_post(path, payload, timeout=180):
    req = urllib.request.Request(
        BASE + path, data=json.dumps(payload).encode(),
        headers={**HDR, "Content-Type": "application/json"}, method="POST")
    try:
        with urllib.request.urlopen(req, timeout=timeout) as r:
            return r.status, json.load(r)
    except urllib.error.HTTPError as e:
        return e.code, e.read().decode()[:800]


def wc_tanpa_skema(s):
    """Hitungan kata yang dipakai laporan: skrip/skema tidak dihitung."""
    t = htmlmod.unescape(re.sub(r"<(script|style).*?</\1>", " ", s, flags=re.S))
    return len(re.sub(r"<[^>]+>", " ", t).split())


def wc_audit(s):
    """Hitungan kata metrik audit (isi skrip ikut dihitung)."""
    t = htmlmod.unescape(s)
    return len(re.sub(r"<[^>]+>", " ", t).split())


# ---------------------------------------------------------------- tarik sebelum
p = rest_get(f"/posts/{PID}?context=edit")
raw = p["content"]["raw"]
open(f"{OUT}/post_{PID}_SEBELUM.html", "w").write(raw)
json.dump(p, open(f"{OUT}/post_{PID}_SEBELUM.json", "w"), ensure_ascii=False, indent=1)
KATA_SEBELUM = wc_tanpa_skema(raw)
KATA_AUDIT_SEBELUM = wc_audit(raw)
meta0 = p.get("meta") or {}
print(f"[sebelum] kata (tanpa skema) = {KATA_SEBELUM} | kata metrik audit = {KATA_AUDIT_SEBELUM}")
print(f"[sebelum] judul : {p['title']['raw']!r}")
print(f"[sebelum] fokus : {meta0.get('_yoast_wpseo_focuskw')!r}")
print(f"[sebelum] slug  : {p['slug']!r} (TIDAK diubah)")
print(f"[sebelum] tanggal: {p['date']} | status: {p['status']}")

# ------------------------------------------------------------------ isi tambahan
KEWAJIBAN = """<!-- wp:heading -->
<h2 class="wp-block-heading">Kewajiban Setelah Badan Usaha Berdiri</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>NIB sering dianggap sebagai garis akhir, padahal dari titik itu kewajiban rutin mulai berjalan. Badan usaha yang terdaftar di OSS wajib menyampaikan Laporan Kegiatan Penanaman Modal (LKPM). Usaha menengah dan besar melaporkannya setiap triwulan, usaha kecil setiap semester, dan usaha mikro dikecualikan dari kewajiban ini. Laporan itu memuat realisasi investasi dan penyerapan tenaga kerja. Kalau dibiarkan kosong, status izin usaha Anda bisa tercatat tidak aktif di sistem OSS.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Dari sisi pajak, perusahaan memerlukan NPWP badan yang terpisah dari NPWP pribadi pengurus dan wajib menyampaikan SPT Tahunan badan. Ketika peredaran bruto usaha melewati Rp4,8 miliar dalam satu tahun buku, Anda wajib dikukuhkan sebagai Pengusaha Kena Pajak dan memungut PPN atas penyerahan barang atau jasa. Untuk PT, ada kewajiban internal yang kerap terlewat: menyelenggarakan rapat umum pemegang saham tahunan dan menyusun laporan keuangan tahunan sebagai bahan rapat.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Perubahan data juga harus dilaporkan. Pergantian direktur, perpindahan alamat, penambahan modal, atau perubahan susunan pemegang saham wajib didaftarkan lewat AHU. Selama tidak dilaporkan, dokumen resmi perusahaan tidak lagi menggambarkan keadaan yang sebenarnya. Biasanya hal ini baru terasa ketika perusahaan mengikuti tender atau mengajukan kredit, saat verifikasi menemukan ketidaksesuaian antara akta, NIB, dan data pajak.</p>
<!-- /wp:paragraph -->"""

DITOLAK = """<!-- wp:heading -->
<h2 class="wp-block-heading">Penyebab Pendaftaran CV atau PT Ditolak</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Sebagian besar penolakan terjadi karena data dan dokumen yang tidak konsisten dengan berkas pendukungnya. Beberapa penyebab yang paling sering muncul:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li>Nama badan usaha sama atau mirip dengan nama yang sudah terdaftar. Siapkan dua atau tiga pilihan alternatif, sebab nama yang ditolak harus diajukan ulang dari awal.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Alamat domisili tidak sesuai peruntukan ruang. Untuk lokasi yang zonanya belum jelas, Anda perlu mengurus konfirmasi Kesesuaian Kegiatan Pemanfaatan Ruang lewat OSS.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Kode Klasifikasi Baku Lapangan Usaha Indonesia (KBLI) tidak sesuai kegiatan nyata. KBLI yang salah membuat daftar izin sektoral yang muncul ikut salah.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Data identitas tidak cocok, misalnya nama pada KTP berbeda dengan NPWP, atau salah satu pendiri berada di luar negeri sehingga tanda tangannya perlu perlakuan khusus.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Akta pendirian belum memenuhi syarat, misalnya maksud dan tujuan terlalu umum atau data pemilik manfaat tidak dicantumkan. Untuk PT, data pemilik manfaat termasuk yang diperiksa saat pengesahan.</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->"""

TENDER = """<!-- wp:heading -->
<h2 class="wp-block-heading">CV atau PT untuk Tender dan Kredit Bank</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Kalau dua hal itu ada dalam rencana Anda, pertimbangkan sejak awal. Sebagian paket pekerjaan bernilai besar dan banyak fasilitas kredit bank mensyaratkan pemohon berbadan hukum. CV bukan badan hukum, jadi berkasnya gugur pada tahap verifikasi begitu persyaratan itu disebutkan secara tegas. Pertanggungjawabannya pun berbeda: sekutu aktif CV menanggung utang usaha sampai harta pribadinya, sedangkan pemegang saham PT tidak menanggung utang perseroan sepanjang modal disetor penuh dan tidak ada penyalahgunaan.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ada satu bentuk lain yang khusus disediakan untuk pelaku usaha kecil. Perseroan Terbatas Perorangan dapat didirikan oleh satu orang tanpa akta notaris, dengan syarat usahanya masuk kriteria usaha mikro atau kecil. Pendiriannya dilakukan lewat surat pernyataan yang didaftarkan secara elektronik ke AHU, sehingga Anda tidak perlu mencari pemegang saham kedua hanya untuk mendapatkan status badan hukum.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Yang perlu diingat, bentuk badan usaha tidak bisa ditukar begitu saja. CV yang berubah menjadi PT berarti membangun badan hukum baru, memindahkan aset, dan menyesuaikan kontrak yang masih berjalan.</p>
<!-- /wp:paragraph -->"""

SENDIRI = """<!-- wp:heading -->
<h2 class="wp-block-heading">Bagian Mana yang Bisa Dikerjakan Sendiri</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Pengurusan NIB dan izin dasar lewat OSS memang bisa Anda kerjakan sendiri, dan banyak pelaku usaha memilih jalan itu. Yang lebih rawan justru bagian yang menyangkut kesepakatan antar pihak: penetapan nama, pemilihan KBLI, penyusunan akta, dan pembagian hak antar pendiri. Bagian ini jarang bermasalah di tahun pertama. Sengketa biasanya baru muncul ketika salah satu pendiri ingin keluar dan tidak ada dokumen yang mengatur cara modalnya dialihkan.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Perbaikan akta yang salah juga menambah pekerjaan. Anda perlu menyusun akta perubahan, mengurus pengesahan ulang, lalu memperbarui data di OSS dan bank. Kalau usaha Anda dijalankan bersama mitra atau sedang bersiap menerima investor, menyiapkan dokumen pendirian sejak awal lebih hemat daripada memperbaikinya di tengah sengketa.</p>
<!-- /wp:paragraph -->"""

KONTEN = raw

# 1) kewajiban rutin, setelah langkah pengurusan NIB
JANGKAR_A = ('<p>Setelah akta terbit, langkah selanjutnya adalah mengurus Nomor Induk '
             'Berusaha (NIB) melalui sistem OSS. NIB berfungsi sebagai identitas usaha '
             'sekaligus izin usaha dasar. Proses ini bisa dilakukan secara mandiri di '
             'oss.go.id.</p>\n<!-- /wp:paragraph -->')
assert KONTEN.count(JANGKAR_A) == 1, "jangkar A tidak unik"
KONTEN = KONTEN.replace(JANGKAR_A, JANGKAR_A + "\n\n" + KEWAJIBAN, 1)

# 2) tiga bagian penutup, tepat sebelum blok FAQ
JANGKAR_B = '<!-- wp:heading -->\n<h2 class="wp-block-heading">Pertanyaan Umum Seputar Pendirian CV dan PT</h2>'
assert KONTEN.count(JANGKAR_B) == 1, "jangkar B tidak unik"
KONTEN = KONTEN.replace(JANGKAR_B, DITOLAK + "\n\n" + TENDER + "\n\n" + SENDIRI + "\n\n" + JANGKAR_B, 1)

KATA_SESUDAH = wc_tanpa_skema(KONTEN)
KATA_AUDIT_SESUDAH = wc_audit(KONTEN)
print(f"\n[kata] tanpa skema {KATA_SEBELUM} -> {KATA_SESUDAH} (+{KATA_SESUDAH - KATA_SEBELUM})")
print(f"[kata] metrik audit {KATA_AUDIT_SEBELUM} -> {KATA_AUDIT_SESUDAH}")
assert KATA_SESUDAH >= 1000, f"target 1.000+ kata belum tercapai ({KATA_SESUDAH})"
assert KATA_SESUDAH <= 1350, f"artikel jadi terlalu panjang ({KATA_SESUDAH})"
assert KATA_SESUDAH > KATA_SEBELUM + 350, "tambahan isi terlalu tipis"

# ------------------------------------------------------------- pemeriksa teks baru
BARU = KEWAJIBAN + DITOLAK + TENDER + SENDIRI
cekal = {
    "em dash": BARU.count("\u2014"),
    "kutip melengkung": len(re.findall(r"[\u2018\u2019\u201c\u201d]", BARU)),
    "CJK": len(re.findall(r"[\u3000-\u9fff]", BARU)),
    "placeholder": len(re.findall(r"\{[A-Za-z_\[0-9]+\}", BARU)),
    "frasa AI": len(re.findall(r"(Di era digital|Dalam dunia yang|Selain itu|Tak dapat dipungkiri|Pada era|Mari kita|perlu diketahui bahwa)",
                              BARU, re.I)),
    "klaim angka tak berdasar": len(re.findall(r"(\d{2,3}\s?%|pasti menang|100%|dijamin)", BARU, re.I)),
    "emoji": len(re.findall(r"[\U0001F300-\U0001FAFF\u2600-\u27BF]", BARU)),
}
print("[periksa teks baru]", cekal)
assert sum(cekal.values()) == 0, "teks baru tidak lolos pemeriksa"

# fakta kunci harus ada apa adanya (sudah dicek lewat pencarian)
assert "usaha kecil setiap semester" in KEWAJIBAN and "usaha mikro dikecualikan" in KEWAJIBAN
assert "Rp4,8 miliar" in KEWAJIBAN
assert "Perseroan Terbatas Perorangan" in TENDER

# ------------------------------------------------------------------ keutuhan lain
for_cek = {
    "tombol WA": KONTEN.count("wa.me/6281909222026"),
    "skema FAQPage": KONTEN.count('"@type": "FAQPage"'),
    "h2": len(re.findall(r"<h2", KONTEN)),
    "h3": len(re.findall(r"<h3", KONTEN)),
    "tautan pilar": KONTEN.count("law-firm-surabaya"),
    "faq blok rank math": KONTEN.count("rank-math-faq-question"),
    "judul lama": KONTEN.count("Cara Daftar CV dan PT Online: Panduan Lengkap Legalitas Usaha 2026"),
}
print("[utuh]", for_cek)
assert for_cek["tombol WA"] == 1, "tombol WA berubah"
assert for_cek["skema FAQPage"] == 1, "skema FAQPage berubah"
assert for_cek["tautan pilar"] == 0, "tautan pilar tidak boleh disentuh hari ini"

# bukti tidak ada bagian lain yang tersentuh: balikkan empat sisipan -> harus identik
BALIK = (KONTEN.replace("\n\n" + KEWAJIBAN, "", 1)
         .replace(DITOLAK + "\n\n" + TENDER + "\n\n" + SENDIRI + "\n\n", "", 1))
assert BALIK == raw, "ada perubahan di luar sisipan yang direncanakan"
print("[integritas] sisa artikel identik dengan versi sebelum (4 sisipan saja)")

if not APPLY:
    open(f"{OUT}/post_{PID}_SESUDAH_dryrun.html", "w").write(KONTEN)
    print("\n[DRY RUN] tidak ada yang dikirim. Jalankan dengan --apply bila sudah benar.")
    sys.exit(0)

payload = {"content": KONTEN}  # judul/meta/slug sengaja tidak dikirim
kode, resp = rest_post(f"/posts/{PID}", payload)
print(f"\n[POST] status {kode}")
json.dump(resp, open(f"{OUT}/post_{PID}_POSTRESP.json", "w"), ensure_ascii=False, indent=1)
if kode != 200:
    print("GAGAL:", resp)
    sys.exit(1)

# ------------------------------------------------------------- baca ulang dari API
q = rest_get(f"/posts/{PID}?context=edit")
raw2 = q["content"]["raw"]
open(f"{OUT}/post_{PID}_SESUDAH.html", "w").write(raw2)
verif = {
    "id": PID, "slug": q["slug"], "status": q["status"], "link": q["link"],
    "modified": q["modified"], "judul": q["title"]["raw"],
    "kata_tanpa_skema_sebelum": KATA_SEBELUM, "kata_tanpa_skema_sesudah": wc_tanpa_skema(raw2),
    "kata_metrik_audit_sebelum": KATA_AUDIT_SEBELUM, "kata_metrik_audit_sesudah": wc_audit(raw2),
    "sisipan_kewajiban": "Kewajiban Setelah Badan Usaha Berdiri" in raw2,
    "sisipan_ditolak": "Penyebab Pendaftaran CV atau PT Ditolak" in raw2,
    "sisipan_tender": "CV atau PT untuk Tender dan Kredit Bank" in raw2,
    "sisipan_sendiri": "Bagian Mana yang Bisa Dikerjakan Sendiri" in raw2,
    "faq_utuh": raw2.count('"@type": "FAQPage"') == 1 and raw2.count("rank-math-faq-question") == 5,
    "tombol_wa": raw2.count("wa.me/6281909222026"),
    "h2": len(re.findall(r"<h2", raw2)), "h3": len(re.findall(r"<h3", raw2)),
    "judul_tidak_berubah": q["title"]["raw"] == p["title"]["raw"],
    "slug_tidak_berubah": q["slug"] == p["slug"],
    "identik_di_luar_sisipan": (raw2.replace("\n\n" + KEWAJIBAN, "", 1)
                                .replace(DITOLAK + "\n\n" + TENDER + "\n\n" + SENDIRI + "\n\n", "", 1)) == raw,
}
json.dump(verif, open(f"{OUT}/post_{PID}_VERIFIKASI.json", "w"), ensure_ascii=False, indent=1)
print("[verifikasi REST]", json.dumps(verif, ensure_ascii=False, indent=1))
