A bank for less Trustworthy Friends
JavaScript (ES6), 91 88 79 bytes

Saved 8 bytes thanks to @NahuelFouilleul

Takes input in currying syntax (a)(b).

a=&gt;b=&gt;b.filter(([x,y,z])=&gt;(a[x]+=z)&lt;0&amp;a[y]&lt;0?a[y]-=z:0,a.map(([x,y])=&gt;a[x]=~y))


Test cases



let f =

a=&gt;b=&gt;b.filter(([x,y,z])=&gt;(a[x]+=z)&lt;0&amp;a[y]&lt;0?a[y]-=z:0,a.map(([x,y])=&gt;a[x]=~y))

console.log(JSON.stringify(f(
  [["Alice", 5], ["Bob", 2]]
)(
  [["Alice", "Bob", 5], ["Bob", "Alice", 7]]
)))

console.log(JSON.stringify(f(
  [["A", 2], ["B", 3], ["C", 5]]
)(
  [["C", "A", 2], ["B", "C", 4], ["A", "B", 2]]
)))

console.log(JSON.stringify(f(
  [["A", 2], ["B", 3]]
)(
  [["A", "B", 2], ["A", "B", 2]]
)))

console.log(JSON.stringify(f(
  [["A", 4], ["B", 0]]
)(
  [["A", "B", 1], ["A", "B", 5], ["A", "B", 2]]
)))

console.log(JSON.stringify(f(
  [["A", 2], ["B", 3], ["C", 4]]
)(
  [["A", "B", 3], ["C", "B", 4]]
)))




Beautified and commented

a =&gt; b =&gt;                 // given the two lists a and b
  b.filter(([x, y, z]) =&gt; // for each (x = payer, y = payee, z = amount) in b:
    (a[x] += z) &lt; 0 &amp;     //   update the payer's account; if it's still valid
    a[y] &lt; 0 ?            //   and the payee's account is also valid:
      a[y] -= z           //     update the payee's account
    :                     //   else:
      0,                  //     do nothing
    a.map(([x, y]) =&gt;     //   initialization: for each (x = owner, y = amount) in a:
      a[x] = ~y           //     set up this account (&gt;= 0: closed, -1: $0, -2: $1, etc.)
    )                     //   end of map()
  )                       // end of filter()